Update camera layout for better support across different screen sizes.

This commit is contained in:
Alex Hart 2022-09-07 14:55:39 -03:00 committed by Greyson Parrelli
parent 993e49db48
commit 24b7593178
20 changed files with 407 additions and 299 deletions

View file

@ -554,7 +554,7 @@
</activity>
<activity android:name=".mediasend.AvatarSelectionActivity"
android:theme="@style/TextSecure.FullScreenMedia"
android:theme="@style/TextSecure.DarkNoActionBar"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".blocked.BlockedUsersActivity"
@ -659,7 +659,7 @@
<activity android:name=".wallpaper.crop.WallpaperImageSelectionActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"
android:theme="@style/TextSecure.FullScreenMedia" />
android:theme="@style/TextSecure.DarkNoActionBar" />
<activity android:name=".wallpaper.crop.WallpaperCropActivity"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"

View file

@ -5,6 +5,7 @@ import android.content.Intent;
import android.graphics.Point;
import android.net.Uri;
import android.os.Bundle;
import android.view.WindowManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
@ -62,6 +63,11 @@ public class AvatarSelectionActivity extends AppCompatActivity implements Camera
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
);
setContentView(R.layout.avatar_selection_activity);
if (isGalleryFirst()) {

View file

@ -27,6 +27,11 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.view.ViewKt;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.MultiTransformation;
@ -48,6 +53,7 @@ import org.thoughtcrime.securesms.stories.viewer.page.StoryDisplay;
import org.thoughtcrime.securesms.util.ServiceUtil;
import org.signal.core.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.io.ByteArrayOutputStream;
@ -125,7 +131,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
View cameraParent = view.findViewById(R.id.camera_preview_parent);
onOrientationChanged(getResources().getConfiguration().orientation);
onOrientationChanged();
cameraPreview.setSurfaceTextureListener(this);
@ -134,7 +140,7 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
// Let's assume portrait for now, so 9:16
float aspectRatio = CameraFragment.getAspectRatioForOrientation(getResources().getConfiguration().orientation);
float aspectRatio = CameraFragment.getAspectRatioForOrientation(Configuration.ORIENTATION_PORTRAIT);
float width = right - left;
float height = Math.min((1f / aspectRatio) * width, bottom - top);
@ -231,12 +237,6 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
});
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onOrientationChanged(newConfig.orientation);
}
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
Log.d(TAG, "onSurfaceTextureAvailable");
@ -322,25 +322,13 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
View galleryButton = requireView().findViewById(R.id.camera_gallery_button);
View countButton = requireView().findViewById(R.id.camera_review_button);
View toggleSpacer = requireView().findViewById(R.id.toggle_spacer);
mostRecentItemDisposable.dispose();
mostRecentItemDisposable = controller.getMostRecentMediaItem()
.observeOn(AndroidSchedulers.mainThread())
.subscribe(item -> presentRecentItemThumbnail(item.orElse(null)));
if (toggleSpacer != null) {
if (Stories.isFeatureEnabled()) {
StoryDisplay storyDisplay = StoryDisplay.Companion.getStoryDisplay(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
if (storyDisplay == StoryDisplay.SMALL) {
toggleSpacer.setVisibility(View.VISIBLE);
} else {
toggleSpacer.setVisibility(View.GONE);
}
} else {
toggleSpacer.setVisibility(View.GONE);
}
}
initializeViewFinderAndControlsPositioning();
captureButton.setOnClickListener(v -> {
captureButton.setEnabled(false);
@ -368,6 +356,27 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
countButton.setOnClickListener(v -> controller.onCameraCountButtonClicked());
}
private void initializeViewFinderAndControlsPositioning() {
CardView cameraCard = requireView().findViewById(R.id.camera_preview_parent);
View controls = requireView().findViewById(R.id.camera_controls_container);
CameraDisplay cameraDisplay = CameraDisplay.getDisplay(requireView());
if (!cameraDisplay.getRoundViewFinderCorners()) {
cameraCard.setRadius(0f);
}
ViewUtil.setBottomMargin(controls, cameraDisplay.getCameraCaptureMarginBottom(getResources()));
if (cameraDisplay.getCameraViewportGravity() == CameraDisplay.CameraViewportGravity.CENTER) {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone((ConstraintLayout) requireView());
constraintSet.connect(R.id.camera_preview_parent, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
constraintSet.applyTo((ConstraintLayout) requireView());
} else {
ViewUtil.setBottomMargin(cameraCard, cameraDisplay.getCameraViewportMarginBottom());
}
}
private void onCaptureClicked() {
orderEnforcer.reset();
@ -426,9 +435,8 @@ public class Camera1Fragment extends LoggingFragment implements CameraFragment,
return new PointF(scaleX, scaleY);
}
private void onOrientationChanged(int orientation) {
int layout = orientation == Configuration.ORIENTATION_PORTRAIT ? R.layout.camera_controls_portrait
: R.layout.camera_controls_landscape;
private void onOrientationChanged() {
int layout = R.layout.camera_controls_portrait;
controlsContainer.removeAllViews();
controlsContainer.addView(LayoutInflater.from(getContext()).inflate(layout, controlsContainer, false));

View file

@ -0,0 +1,139 @@
package org.thoughtcrime.securesms.mediasend
import android.content.res.Resources
import android.view.View
import androidx.annotation.Dimension
import androidx.annotation.Px
import androidx.window.WindowManager
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.stories.Stories
/**
* Description of the Camera Viewport, Controls, and Toggle position information.
*/
enum class CameraDisplay(
private val aspectRatio: Float,
val roundViewFinderCorners: Boolean,
private val withTogglePositionInfo: PositionInfo,
private val withoutTogglePositionInfo: PositionInfo,
@Dimension(unit = Dimension.DP) private val toggleBottomMargin: Int
) {
DISPLAY_20_9(
aspectRatio = 9f / 20f,
roundViewFinderCorners = true,
withTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 130,
cameraViewportMarginBottomDp = 106,
cameraViewportGravity = CameraViewportGravity.BOTTOM
),
withoutTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 130,
cameraViewportGravity = CameraViewportGravity.CENTER
),
toggleBottomMargin = 52
),
DISPLAY_19_9(
aspectRatio = 9f / 19f,
roundViewFinderCorners = true,
withTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 128,
cameraViewportMarginBottomDp = 104,
cameraViewportGravity = CameraViewportGravity.BOTTOM
),
withoutTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 128,
cameraViewportGravity = CameraViewportGravity.CENTER
),
toggleBottomMargin = 52
),
DISPLAY_18_9(
aspectRatio = 9f / 18f,
roundViewFinderCorners = true,
withTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 120,
cameraViewportGravity = CameraViewportGravity.CENTER
),
withoutTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 84,
cameraViewportGravity = CameraViewportGravity.CENTER
),
toggleBottomMargin = 54
),
DISPLAY_16_9(
aspectRatio = 9f / 16f,
roundViewFinderCorners = false,
withTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 120,
cameraViewportGravity = CameraViewportGravity.BOTTOM
),
withoutTogglePositionInfo = PositionInfo(
cameraCaptureMarginBottomDp = 84,
cameraViewportGravity = CameraViewportGravity.BOTTOM
),
toggleBottomMargin = 54
);
@Px
fun getCameraCaptureMarginBottom(resources: Resources): Int {
val positionInfo = if (Stories.isFeatureEnabled()) withTogglePositionInfo else withoutTogglePositionInfo
return positionInfo.cameraCaptureMarginBottomDp.dp - getCameraButtonSizeOffset(resources)
}
@Px
fun getCameraViewportMarginBottom(): Int {
val positionInfo = if (Stories.isFeatureEnabled()) withTogglePositionInfo else withoutTogglePositionInfo
return positionInfo.cameraViewportMarginBottomDp.dp
}
fun getCameraViewportGravity(): CameraViewportGravity {
val positionInfo = if (Stories.isFeatureEnabled()) withTogglePositionInfo else withoutTogglePositionInfo
return positionInfo.cameraViewportGravity
}
@Px
fun getToggleBottomMargin(): Int {
return toggleBottomMargin.dp
}
companion object {
@Px
@JvmStatic
private fun getCameraButtonSizeOffset(resources: Resources): Int {
val cameraCaptureButtonSize = resources.getDimensionPixelSize(R.dimen.camera_capture_button_size)
val cameraCaptureImageButtonSize = resources.getDimensionPixelSize(R.dimen.camera_capture_image_button_size)
return (cameraCaptureButtonSize - cameraCaptureImageButtonSize) / 2
}
@JvmStatic
fun getDisplay(view: View): CameraDisplay {
val windowManager = WindowManager(view.context)
val windowMetrics = windowManager.getCurrentWindowMetrics()
val width = windowMetrics.bounds.width()
val height = windowMetrics.bounds.height()
val aspectRatio = width.toFloat() / height
return when {
aspectRatio <= DISPLAY_20_9.aspectRatio -> DISPLAY_20_9
aspectRatio <= DISPLAY_19_9.aspectRatio -> DISPLAY_19_9
aspectRatio <= DISPLAY_18_9.aspectRatio -> DISPLAY_18_9
else -> DISPLAY_16_9
}
}
}
enum class CameraViewportGravity {
CENTER,
BOTTOM
}
data class PositionInfo(
@Dimension(unit = Dimension.DP) val cameraCaptureMarginBottomDp: Int,
@Dimension(unit = Dimension.DP) val cameraViewportMarginBottomDp: Int = 0,
val cameraViewportGravity: CameraViewportGravity
)
}

View file

@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.mediasend;
import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.camera.view.video.ExperimentalVideo;

View file

@ -25,21 +25,23 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.camera.core.AspectRatio;
import androidx.camera.core.CameraSelector;
import androidx.camera.core.ImageCapture;
import androidx.camera.core.ImageCaptureException;
import androidx.camera.core.ImageProxy;
import androidx.camera.core.Preview;
import androidx.camera.view.CameraController;
import androidx.camera.view.LifecycleCameraController;
import androidx.camera.view.PreviewView;
import androidx.camera.view.video.ExperimentalVideo;
import androidx.cardview.widget.CardView;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
import androidx.core.content.ContextCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.util.Executors;
import org.signal.core.util.Stopwatch;
import org.signal.core.util.concurrent.SimpleTask;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.LoggingFragment;
@ -52,11 +54,9 @@ import org.thoughtcrime.securesms.mediasend.v2.MediaAnimations;
import org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton;
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader.DecryptableUri;
import org.thoughtcrime.securesms.mms.MediaConstraints;
import org.thoughtcrime.securesms.stories.Stories;
import org.thoughtcrime.securesms.stories.viewer.page.StoryDisplay;
import org.thoughtcrime.securesms.util.MemoryFileDescriptor;
import org.signal.core.util.Stopwatch;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.ViewUtil;
import org.thoughtcrime.securesms.video.VideoUtil;
import java.io.FileDescriptor;
@ -147,11 +147,11 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
previewView.setScaleType(PREVIEW_SCALE_TYPE);
previewView.setController(cameraController);
onOrientationChanged(getResources().getConfiguration().orientation);
onOrientationChanged();
view.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
// Let's assume portrait for now, so 9:16
float aspectRatio = CameraFragment.getAspectRatioForOrientation(getResources().getConfiguration().orientation);
float aspectRatio = CameraFragment.getAspectRatioForOrientation(Configuration.ORIENTATION_PORTRAIT);
float width = right - left;
float height = Math.min((1f / aspectRatio) * width, bottom - top);
@ -176,6 +176,11 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onDestroyView() {
super.onDestroyView();
@ -184,12 +189,6 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
}
@Override
public void onConfigurationChanged(@NonNull Configuration newConfig) {
super.onConfigurationChanged(newConfig);
onOrientationChanged(newConfig.orientation);
}
@Override
public void fadeOutControls(@NonNull Runnable onEndAction) {
controlsContainer.setEnabled(false);
@ -221,12 +220,11 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
});
}
private void onOrientationChanged(int orientation) {
int layout = orientation == Configuration.ORIENTATION_PORTRAIT ? R.layout.camera_controls_portrait
: R.layout.camera_controls_landscape;
private void onOrientationChanged() {
int layout = R.layout.camera_controls_portrait;
int resolution = CameraXUtil.getIdealResolution(Resources.getSystem().getDisplayMetrics().widthPixels, Resources.getSystem().getDisplayMetrics().heightPixels);
Size size = CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, orientation == Configuration.ORIENTATION_PORTRAIT);
Size size = CameraXUtil.buildResolutionForRatio(resolution, ASPECT_RATIO_16_9, true);
CameraController.OutputSize outputSize = new CameraController.OutputSize(size);
cameraController.setImageCaptureTargetSize(outputSize);
@ -280,6 +278,27 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
}
}
private void initializeViewFinderAndControlsPositioning() {
CardView cameraCard = requireView().findViewById(R.id.camerax_camera_parent);
View controls = requireView().findViewById(R.id.camerax_controls_container);
CameraDisplay cameraDisplay = CameraDisplay.getDisplay(requireView());
if (!cameraDisplay.getRoundViewFinderCorners()) {
cameraCard.setRadius(0f);
}
ViewUtil.setBottomMargin(controls, cameraDisplay.getCameraCaptureMarginBottom(getResources()));
if (cameraDisplay.getCameraViewportGravity() == CameraDisplay.CameraViewportGravity.CENTER) {
ConstraintSet constraintSet = new ConstraintSet();
constraintSet.clone((ConstraintLayout) requireView());
constraintSet.connect(R.id.camerax_camera_parent, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP);
constraintSet.applyTo((ConstraintLayout) requireView());
} else {
ViewUtil.setBottomMargin(cameraCard, cameraDisplay.getCameraViewportMarginBottom());
}
}
@SuppressLint({ "ClickableViewAccessibility", "MissingPermission" })
private void initControls() {
View flipButton = requireView().findViewById(R.id.camera_flip_button);
@ -287,20 +306,8 @@ public class CameraXFragment extends LoggingFragment implements CameraFragment {
View galleryButton = requireView().findViewById(R.id.camera_gallery_button);
View countButton = requireView().findViewById(R.id.camera_review_button);
CameraXFlashToggleView flashButton = requireView().findViewById(R.id.camera_flash_button);
View toggleSpacer = requireView().findViewById(R.id.toggle_spacer);
if (toggleSpacer != null) {
if ( Stories.isFeatureEnabled()) {
StoryDisplay storyDisplay = StoryDisplay.Companion.getStoryDisplay(getResources().getDisplayMetrics().widthPixels, getResources().getDisplayMetrics().heightPixels);
if (storyDisplay == StoryDisplay.SMALL) {
toggleSpacer.setVisibility(View.VISIBLE);
} else {
toggleSpacer.setVisibility(View.GONE);
}
} else {
toggleSpacer.setVisibility(View.GONE);
}
}
initializeViewFinderAndControlsPositioning();
mostRecentItemDisposable.dispose();
mostRecentItemDisposable = controller.getMostRecentMediaItem()

View file

@ -6,6 +6,8 @@ import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.KeyEvent
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.activity.viewModels
@ -13,6 +15,7 @@ import androidx.appcompat.app.AppCompatDelegate
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.content.ContextCompat
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.ViewModelProvider
import androidx.navigation.Navigation
import androidx.navigation.fragment.NavHostFragment
@ -29,6 +32,7 @@ import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
import org.thoughtcrime.securesms.mediasend.CameraDisplay
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.v2.review.MediaReviewFragment
@ -80,6 +84,10 @@ class MediaSelectionActivity :
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
setContentView(R.layout.media_selection_activity)
window.addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
)
val sendType: MessageSendType = requireNotNull(intent.getParcelableExtra(MESSAGE_SEND_TYPE))
val initialMedia: List<Media> = intent.getParcelableArrayListExtra(MEDIA) ?: listOf()
val message: CharSequence? = if (shareToTextStory) null else draftText
@ -89,6 +97,12 @@ class MediaSelectionActivity :
viewModel = ViewModelProvider(this, factory)[MediaSelectionViewModel::class.java]
val textStoryToggle: ConstraintLayout = findViewById(R.id.switch_widget)
val cameraDisplay = CameraDisplay.getDisplay(textStoryToggle)
textStoryToggle.updateLayoutParams<FrameLayout.LayoutParams> {
bottomMargin = cameraDisplay.getToggleBottomMargin()
}
val cameraSelectedConstraintSet = ConstraintSet().apply {
clone(textStoryToggle)
}

View file

@ -3,20 +3,20 @@ package org.thoughtcrime.securesms.mediasend.v2.gallery
import android.os.Bundle
import android.view.View
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.Toolbar
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Transformations
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import org.signal.core.util.Stopwatch
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.recyclerview.GridDividerDecoration
import org.thoughtcrime.securesms.databinding.V2MediaGalleryFragmentBinding
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaRepository
import org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
@ -36,12 +36,6 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
private lateinit var callbacks: Callbacks
private lateinit var toolbar: Toolbar
private lateinit var galleryRecycler: RecyclerView
private lateinit var countButton: MediaCountIndicatorButton
private lateinit var bottomBarGroup: View
private lateinit var selectedRecycler: RecyclerView
private var selectedMediaTouchHelper: ItemTouchHelper? = null
private val galleryAdapter = MappingAdapter()
@ -57,29 +51,39 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
callbacks = requireListener()
val binding = V2MediaGalleryFragmentBinding.bind(view)
toolbar = view.findViewById(R.id.media_gallery_toolbar)
galleryRecycler = view.findViewById(R.id.media_gallery_grid)
selectedRecycler = view.findViewById(R.id.media_gallery_selected)
countButton = view.findViewById(R.id.media_gallery_count_button)
bottomBarGroup = view.findViewById(R.id.media_gallery_bottom_bar_group)
binding.root.setPadding(
0,
0,
0,
ViewUtil.getNavigationBarHeight(view)
)
(galleryRecycler.layoutManager as GridLayoutManager).spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
binding.mediaGalleryToolbar.updateLayoutParams<ConstraintLayout.LayoutParams> {
topMargin = ViewUtil.getStatusBarHeight(view)
}
binding.mediaGalleryStatusBarBackground.updateLayoutParams {
height = ViewUtil.getStatusBarHeight(view)
}
(binding.mediaGalleryGrid.layoutManager as GridLayoutManager).spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() {
override fun getSpanSize(position: Int): Int {
val isFolder: Boolean = (galleryRecycler.adapter as MappingAdapter).getModel(position).map { it is MediaGallerySelectableItem.FolderModel }.orElse(false)
val isFolder: Boolean = (binding.mediaGalleryGrid.adapter as MappingAdapter).getModel(position).map { it is MediaGallerySelectableItem.FolderModel }.orElse(false)
return if (isFolder) 2 else 1
}
}
toolbar.setNavigationOnClickListener {
binding.mediaGalleryToolbar.setNavigationOnClickListener {
onBack()
}
Material3OnScrollHelper(requireActivity(), toolbar).attach(galleryRecycler)
Material3OnScrollHelper(requireActivity(), listOf(binding.mediaGalleryToolbar, binding.mediaGalleryStatusBarBackground)).attach(binding.mediaGalleryGrid)
if (callbacks.isCameraEnabled()) {
toolbar.setOnMenuItemClickListener { item ->
binding.mediaGalleryToolbar.setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_camera) {
callbacks.onNavigateToCamera()
true
@ -88,18 +92,18 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
}
}
} else {
toolbar.menu.findItem(R.id.action_camera).isVisible = false
binding.mediaGalleryToolbar.menu.findItem(R.id.action_camera).isVisible = false
}
countButton.setOnClickListener {
binding.mediaGalleryCountButton.setOnClickListener {
callbacks.onSubmit()
}
MediaGallerySelectedItem.register(selectedAdapter) { media ->
callbacks.onSelectedMediaClicked(media)
}
selectedRecycler.adapter = selectedAdapter
selectedMediaTouchHelper?.attachToRecyclerView(selectedRecycler)
binding.mediaGallerySelected.adapter = selectedAdapter
selectedMediaTouchHelper?.attachToRecyclerView(binding.mediaGallerySelected)
MediaGallerySelectableItem.registerAdapter(
mappingAdapter = galleryAdapter,
@ -117,25 +121,25 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
callbacks.isMultiselectEnabled()
)
galleryRecycler.adapter = galleryAdapter
galleryRecycler.addItemDecoration(GridDividerDecoration(4, ViewUtil.dpToPx(2)))
binding.mediaGalleryGrid.adapter = galleryAdapter
binding.mediaGalleryGrid.addItemDecoration(GridDividerDecoration(4, ViewUtil.dpToPx(2)))
viewStateLiveData.observe(viewLifecycleOwner) { state ->
bottomBarGroup.visible = state.selectedMedia.isNotEmpty()
countButton.setCount(state.selectedMedia.size)
binding.mediaGalleryBottomBarGroup.visible = state.selectedMedia.isNotEmpty()
binding.mediaGalleryCountButton.setCount(state.selectedMedia.size)
val stopwatch = Stopwatch("mediaSubmit")
selectedAdapter.submitList(state.selectedMedia.map { MediaGallerySelectedItem.Model(it) }) {
stopwatch.split("after-submit")
stopwatch.stop("MediaGalleryFragment")
if (state.selectedMedia.isNotEmpty()) {
selectedRecycler.smoothScrollToPosition(state.selectedMedia.size - 1)
binding.mediaGallerySelected.smoothScrollToPosition(state.selectedMedia.size - 1)
}
}
}
viewModel.state.observe(viewLifecycleOwner) { state ->
toolbar.title = state.bucketTitle ?: requireContext().getString(R.string.AttachmentKeyboard_gallery)
binding.mediaGalleryToolbar.title = state.bucketTitle ?: requireContext().getString(R.string.AttachmentKeyboard_gallery)
}
val galleryItemsWithSelection = LiveDataUtil.combineLatest(

View file

@ -42,6 +42,7 @@ import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.MediaUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
import org.thoughtcrime.securesms.util.views.TouchInterceptingFrameLayout
@ -90,6 +91,13 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment) {
callback = requireListener()
view.setPadding(
0,
ViewUtil.getStatusBarHeight(view),
0,
ViewUtil.getNavigationBarHeight(view)
)
drawToolButton = view.findViewById(R.id.draw_tool)
cropAndRotateButton = view.findViewById(R.id.crop_and_rotate_tool)
qualityButton = view.findViewById(R.id.quality_selector)

View file

@ -4,10 +4,11 @@ import android.content.pm.ActivityInfo
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.widget.AppCompatImageView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
import androidx.core.view.drawToBitmap
import androidx.core.view.postDelayed
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
@ -15,8 +16,10 @@ import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
import org.thoughtcrime.securesms.databinding.StoriesTextPostCreationFragmentBinding
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
import org.thoughtcrime.securesms.mediasend.CameraDisplay
import org.thoughtcrime.securesms.mediasend.v2.HudCommand
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionViewModel
import org.thoughtcrime.securesms.mediasend.v2.stories.StoriesMultiselectForwardActivity
@ -24,18 +27,14 @@ import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendReposi
import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendResult
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.stories.StoryTextPostView
import org.thoughtcrime.securesms.util.LifecycleDisposable
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.visible
class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creation_fragment), TextStoryPostTextEntryFragment.Callback, SafetyNumberBottomSheet.Callbacks {
private lateinit var scene: ConstraintLayout
private lateinit var backgroundButton: AppCompatImageView
private lateinit var send: View
private lateinit var storyTextPostView: StoryTextPostView
private lateinit var sendInProgressCard: View
private var _binding: StoriesTextPostCreationFragmentBinding? = null
private val binding: StoriesTextPostCreationFragmentBinding get() = _binding!!
private val sharedViewModel: MediaSelectionViewModel by viewModels(
ownerProducer = {
@ -66,16 +65,9 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
scene = view.findViewById(R.id.scene)
backgroundButton = view.findViewById(R.id.background_selector)
send = view.findViewById(R.id.send)
storyTextPostView = view.findViewById(R.id.story_text_post)
sendInProgressCard = view.findViewById(R.id.send_in_progress_indicator)
_binding = StoriesTextPostCreationFragmentBinding.bind(view)
val backgroundProtection: View = view.findViewById(R.id.background_protection)
val addLinkProtection: View = view.findViewById(R.id.add_link_protection)
storyTextPostView.showCloseButton()
binding.storyTextPost.showCloseButton()
lifecycleDisposable.bindTo(viewLifecycleOwner)
lifecycleDisposable += sharedViewModel.hudCommands.subscribe {
@ -85,12 +77,12 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
}
viewModel.typeface.observe(viewLifecycleOwner) { typeface ->
storyTextPostView.setTypeface(typeface)
binding.storyTextPost.setTypeface(typeface)
}
viewModel.state.observe(viewLifecycleOwner) { state ->
backgroundButton.background = state.backgroundColor.chatBubbleMask
storyTextPostView.bindFromCreationState(state)
binding.backgroundSelector.background = state.backgroundColor.chatBubbleMask
binding.storyTextPost.bindFromCreationState(state)
if (state.linkPreviewUri != null) {
linkPreviewViewModel.onTextChanged(requireContext(), state.linkPreviewUri, 0, state.linkPreviewUri.lastIndex)
@ -99,32 +91,32 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
}
val canSend = state.body.isNotEmpty() || !state.linkPreviewUri.isNullOrEmpty()
send.alpha = if (canSend) 1f else 0.5f
send.isEnabled = canSend
binding.send.alpha = if (canSend) 1f else 0.5f
binding.send.isEnabled = canSend
}
LiveDataUtil.combineLatest(viewModel.state, linkPreviewViewModel.linkPreviewState) { viewState, linkState ->
Pair(viewState.body.isBlank(), linkState)
}.observe(viewLifecycleOwner) { (useLargeThumb, linkState) ->
storyTextPostView.bindLinkPreviewState(linkState, View.GONE, useLargeThumb)
storyTextPostView.postAdjustLinkPreviewTranslationY()
binding.storyTextPost.bindLinkPreviewState(linkState, View.GONE, useLargeThumb)
binding.storyTextPost.postAdjustLinkPreviewTranslationY()
}
storyTextPostView.setTextViewClickListener {
storyTextPostView.hidePostContent()
storyTextPostView.isEnabled = false
binding.storyTextPost.setTextViewClickListener {
binding.storyTextPost.hidePostContent()
binding.storyTextPost.isEnabled = false
TextStoryPostTextEntryFragment().show(childFragmentManager, null)
}
backgroundProtection.setOnClickListener {
binding.backgroundProtection.setOnClickListener {
viewModel.cycleBackgroundColor()
}
addLinkProtection.setOnClickListener {
binding.addLinkProtection.setOnClickListener {
TextStoryPostLinkEntryFragment().show(childFragmentManager, null)
}
storyTextPostView.setLinkPreviewCloseListener {
binding.storyTextPost.setLinkPreviewCloseListener {
viewModel.setLinkPreview("")
}
@ -132,23 +124,23 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
if (it.isNotEmpty()) {
performSend(it.toSet())
} else {
send.isClickable = true
sendInProgressCard.visible = false
binding.send.isClickable = true
binding.sendInProgressIndicator.visible = false
}
}
send.setOnClickListener {
send.isClickable = false
sendInProgressCard.visible = true
binding.send.setOnClickListener {
binding.send.isClickable = false
binding.sendInProgressIndicator.visible = true
storyTextPostView.hideCloseButton()
binding.storyTextPost.hideCloseButton()
val contacts = (sharedViewModel.destination.getRecipientSearchKeyList() + sharedViewModel.destination.getRecipientSearchKey())
.filterIsInstance(ContactSearchKey::class.java)
.toSet()
if (contacts.isEmpty()) {
val bitmap = storyTextPostView.drawToBitmap()
val bitmap = binding.storyTextPost.drawToBitmap()
viewModel.compressToBlob(bitmap).observeOn(AndroidSchedulers.mainThread()).subscribe { uri ->
launcher.launch(
StoriesMultiselectForwardActivity.Args(
@ -166,18 +158,54 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
performSend(contacts)
}
}
initializeScenePositioning()
}
override fun onResume() {
super.onResume()
storyTextPostView.showCloseButton()
binding.storyTextPost.showCloseButton()
requireActivity().requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
override fun onTextStoryPostTextEntryDismissed() {
storyTextPostView.postDelayed(resources.getInteger(R.integer.text_entry_exit_duration).toLong()) {
storyTextPostView.showPostContent()
storyTextPostView.isEnabled = true
binding.storyTextPost.postDelayed(resources.getInteger(R.integer.text_entry_exit_duration).toLong()) {
binding.storyTextPost.showPostContent()
binding.storyTextPost.isEnabled = true
}
}
private fun initializeScenePositioning() {
val cameraDisplay = CameraDisplay.getDisplay(requireView())
if (!cameraDisplay.roundViewFinderCorners) {
binding.storyTextPostCard.radius = 0f
}
binding.send.updateLayoutParams<ConstraintLayout.LayoutParams> {
bottomMargin = cameraDisplay.getToggleBottomMargin()
}
listOf(binding.backgroundProtection, binding.addLinkProtection).forEach {
it.updateLayoutParams<ConstraintLayout.LayoutParams> {
bottomMargin += cameraDisplay.getCameraCaptureMarginBottom(resources)
}
}
if (cameraDisplay.getCameraViewportGravity() == CameraDisplay.CameraViewportGravity.CENTER) {
val constraintSet = ConstraintSet()
constraintSet.clone(binding.scene)
constraintSet.connect(R.id.story_text_post_card, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.TOP)
constraintSet.applyTo(binding.scene)
} else {
binding.storyTextPostCard.updateLayoutParams<ConstraintLayout.LayoutParams> {
bottomMargin = cameraDisplay.getCameraViewportMarginBottom()
}
}
}
@ -196,8 +224,8 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
requireActivity().finish()
}
is TextStoryPostSendResult.UntrustedRecordsError -> {
send.isClickable = true
sendInProgressCard.visible = false
binding.send.isClickable = true
binding.sendInProgressIndicator.visible = false
SafetyNumberBottomSheet
.forIdentityRecordsAndDestinations(result.untrustedRecords, contacts.toList())

View file

@ -224,6 +224,15 @@ public final class ImageEditorFragment extends Fragment implements ImageEditorHu
Mode mode = Mode.getByCode(requireArguments().getString(KEY_MODE));
if (mode == Mode.AVATAR_CAPTURE || mode == Mode.AVATAR_EDIT) {
view.setPadding(
0,
ViewUtil.getStatusBarHeight(view),
0,
ViewUtil.getNavigationBarHeight(view)
);
}
imageEditorHud = view.findViewById(R.id.scribble_hud);
imageEditorView = view.findViewById(R.id.image_editor_view);

View file

@ -4,6 +4,7 @@ import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -40,6 +41,11 @@ public final class WallpaperImageSelectionActivity extends AppCompatActivity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
);
setContentView(R.layout.wallpaper_image_selection_activity);
getSupportFragmentManager().beginTransaction()

View file

@ -1,96 +0,0 @@
<?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"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<org.thoughtcrime.securesms.mediasend.CameraButtonView
android:id="@+id/camera_capture_button"
android:layout_width="96dp"
android:layout_height="96dp"
android:layout_marginEnd="18dp"
android:contentDescription="@string/CameraXFragment_capture_description"
app:imageCaptureSize="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:recordSize="42dp" />
<org.thoughtcrime.securesms.mediasend.camerax.CameraXFlashToggleView
android:id="@+id/camera_flash_button"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:layout_marginTop="14dp"
android:background="@drawable/circle_transparent_black_40"
android:padding="6dp"
android:src="@drawable/camerax_flash_toggle"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatImageButton
android:id="@+id/camera_flip_button"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="36dp"
android:layout_marginEnd="40dp"
android:background="@drawable/media_selection_camera_switch_background"
android:contentDescription="@string/CameraXFragment_change_camera_description"
android:scaleType="centerInside"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_switch_camera_28"
tools:visibility="visible" />
<FrameLayout
android:id="@+id/camera_gallery_button_background"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="40dp"
android:layout_marginBottom="36dp"
android:background="@drawable/circle_tintable"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/camera_gallery_button"
android:layout_width="52dp"
android:layout_height="52dp"
android:contentDescription="@string/CameraXFragment_open_gallery_description"
android:padding="2dp"
android:scaleType="centerCrop"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.Circle"
tools:src="@color/black" />
</FrameLayout>
<org.thoughtcrime.securesms.mediasend.v2.MediaCountIndicatorButton
android:id="@+id/camera_review_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="40dp"
android:layout_marginBottom="36dp"
android:background="@drawable/v2_media_count_indicator_background"
android:minHeight="44dp"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@id/camera_capture_button"
tools:visibility="visible" />
<View
android:id="@+id/camera_selfie_flash"
android:layout_width="0dp"
android:layout_height="0dp"
android:alpha="0"
android:background="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -8,11 +8,11 @@
<org.thoughtcrime.securesms.mediasend.CameraButtonView
android:id="@+id/camera_capture_button"
android:layout_width="124dp"
android:layout_height="124dp"
android:layout_width="@dimen/camera_capture_button_size"
android:layout_height="@dimen/camera_capture_button_size"
android:contentDescription="@string/CameraXFragment_capture_description"
app:imageCaptureSize="76dp"
app:layout_constraintBottom_toTopOf="@id/toggle_spacer"
app:imageCaptureSize="@dimen/camera_capture_image_button_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:recordSize="54dp" />
@ -40,7 +40,7 @@
android:contentDescription="@string/CameraXFragment_change_camera_description"
android:scaleType="centerInside"
android:visibility="gone"
app:layout_constraintBottom_toTopOf="@id/toggle_spacer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_switch_camera_28"
tools:visibility="visible" />
@ -52,7 +52,7 @@
android:layout_marginEnd="40dp"
android:layout_marginBottom="36dp"
android:background="@drawable/circle_tintable"
app:layout_constraintBottom_toTopOf="@id/toggle_spacer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.imageview.ShapeableImageView
@ -91,14 +91,5 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/toggle_spacer"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -12,7 +12,7 @@
android:layout_height="wrap_content"
app:cardCornerRadius="18dp"
app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintBottom_toBottomOf="parent">
<TextureView
android:id="@+id/camera_preview"
@ -25,7 +25,7 @@
android:id="@+id/camera_controls_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/camera_preview_parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="@id/camera_preview_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:viewBindingIgnore="true">
<androidx.cardview.widget.CardView
android:id="@+id/camerax_camera_parent"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_height="wrap_content"
app:cardCornerRadius="18dp"
app:cardElevation="0dp"
app:layout_constraintTop_toTopOf="parent">
app:layout_constraintBottom_toBottomOf="parent">
<androidx.camera.view.PreviewView
android:id="@+id/camerax_camera"
@ -26,7 +26,7 @@
android:id="@+id/camerax_controls_container"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@id/camerax_camera_parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="@id/camerax_camera_parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View file

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:viewBindingIgnore="true">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
@ -15,8 +15,7 @@
android:id="@+id/switch_widget"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="bottom|center_horizontal"
android:layout_marginBottom="8dp">
android:layout_gravity="bottom|center_horizontal">
<View
android:id="@+id/selected_pill"
@ -31,8 +30,9 @@
<TextView
android:id="@+id/camera_switch"
android:layout_width="wrap_content"
android:layout_height="36sp"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="36sp"
android:paddingHorizontal="18dp"
android:shadowColor="@color/black"
android:text="@string/MediaSelectionActivity__camera"
@ -47,8 +47,9 @@
<TextView
android:id="@+id/text_switch"
android:layout_width="wrap_content"
android:layout_height="36sp"
android:layout_height="wrap_content"
android:gravity="center"
android:minHeight="36sp"
android:paddingHorizontal="18dp"
android:shadowColor="@color/black"
android:shadowRadius="3"

View file

@ -1,7 +1,6 @@
<?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"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/scene"
android:layout_width="match_parent"
@ -11,15 +10,12 @@
android:id="@+id/story_text_post_card"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="12dp"
app:cardCornerRadius="18dp"
app:cardElevation="0dp"
app:layout_constraintBottom_toTopOf="@id/toggle_spacer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="9:16"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0">
app:layout_constraintStart_toStartOf="parent">
<org.thoughtcrime.securesms.stories.StoryTextPostView
android:id="@+id/story_text_post"
@ -36,7 +32,7 @@
android:layout_marginBottom="6dp"
android:padding="2dp"
android:src="@drawable/circle_tintable"
app:layout_constraintBottom_toTopOf="@id/button_bar_barrier"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@id/story_text_post_card"
app:tint="@color/transparent_black_40" />
@ -60,7 +56,7 @@
android:layout_marginBottom="6dp"
android:padding="2dp"
android:src="@drawable/circle_tintable"
app:layout_constraintBottom_toTopOf="@id/button_bar_barrier"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/background_protection"
app:tint="@color/transparent_black_40" />
@ -84,35 +80,12 @@
android:background="@color/signal_colorOnSecondaryContainer"
android:padding="4dp"
android:scaleType="centerInside"
app:layout_constraintBottom_toBottomOf="@id/toggle_spacer"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/toggle_spacer"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.Circle"
app:srcCompat="@drawable/ic_arrow_end_24"
app:tint="@color/signal_colorSecondaryContainer" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/button_bar_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="top"
app:constraint_referenced_ids="barrier_helper,toggle_spacer" />
<View
android:id="@+id/barrier_helper"
android:layout_width="1dp"
android:layout_height="1dp"
app:layout_constraintTop_toBottomOf="@id/story_text_post_card" />
<View
android:id="@+id/toggle_spacer"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<androidx.cardview.widget.CardView
android:id="@+id/send_in_progress_indicator"
android:layout_width="wrap_content"

View file

@ -1,11 +1,17 @@
<?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"
tools:viewBindingIgnore="true"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/media_gallery_status_bar_background"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@id/media_gallery_toolbar"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/media_gallery_toolbar"
android:layout_width="match_parent"

View file

@ -31,6 +31,8 @@
<dimen name="album_5_cell_size_small">69dp</dimen>
<dimen name="camera_contacts_horizontal_margin">16dp</dimen>
<dimen name="camera_capture_button_size">124dp</dimen>
<dimen name="camera_capture_image_button_size">76dp</dimen>
<dimen name="message_corner_radius">18dp</dimen>
<dimen name="message_corner_collapse_radius">4dp</dimen>