mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-08-04 20:34:14 +01:00
More edge-to-edge support.
This commit is contained in:
committed by
Michelle Tang
parent
a57572cf64
commit
bd5c60d442
@@ -974,7 +974,6 @@ class MainActivity :
|
||||
onSetToolbarColor = {
|
||||
toolbarViewModel.setToolbarColor(it)
|
||||
},
|
||||
setStatusBarColor = {},
|
||||
lifecycleOwner = lifecycleOwner
|
||||
).attach(recyclerView)
|
||||
}
|
||||
@@ -984,7 +983,6 @@ class MainActivity :
|
||||
activity = this,
|
||||
views = listOf(chatFolders),
|
||||
viewStubs = listOf(),
|
||||
setStatusBarColor = {},
|
||||
onSetToolbarColor = {
|
||||
toolbarViewModel.setToolbarColor(it)
|
||||
},
|
||||
|
||||
@@ -63,6 +63,7 @@ class TextAvatarCreationFragment : Fragment(R.layout.text_avatar_creation_fragme
|
||||
val tabLayout: ControllableTabLayout = view.findViewById(R.id.text_avatar_creation_tabs)
|
||||
val doneButton: View = view.findViewById(R.id.text_avatar_creation_done)
|
||||
val keyboardAwareLayout: KeyboardAwareLinearLayout = view.findViewById(R.id.keyboard_aware_layout)
|
||||
keyboardAwareLayout.setInsetPaddingMode(KeyboardAwareLinearLayout.InsetPaddingMode.SAFE_AREA)
|
||||
|
||||
withRecyclerSet.load(requireContext(), R.layout.text_avatar_creation_fragment_content)
|
||||
withoutRecyclerSet.load(requireContext(), R.layout.text_avatar_creation_fragment_content_hidden_recycler)
|
||||
|
||||
+2
@@ -21,6 +21,7 @@ import org.signal.donations.InAppPaymentType
|
||||
import org.thoughtcrime.securesms.MainActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.InputAwareLayout
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
@@ -94,6 +95,7 @@ class GiftFlowConfirmationFragment :
|
||||
.create()
|
||||
|
||||
inputAwareLayout = requireView().findViewById(R.id.input_aware_layout)
|
||||
inputAwareLayout.setInsetPaddingMode(KeyboardAwareLinearLayout.InsetPaddingMode.KEYBOARD_AND_NAVIGATION_BAR)
|
||||
emojiKeyboard = requireView().findViewById(R.id.emoji_drawer)
|
||||
|
||||
emojiKeyboard.setFragmentManager(childFragmentManager)
|
||||
|
||||
+1
-2
@@ -50,8 +50,7 @@ class SelectFeaturedBadgeFragment : DSLSettingsFragment(
|
||||
return Material3OnScrollHelper(
|
||||
activity = requireActivity(),
|
||||
views = listOf(scrollShadow),
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
setStatusBarColor = {}
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+10
-1
@@ -11,7 +11,9 @@ import android.view.WindowManager
|
||||
import androidx.activity.compose.LocalOnBackPressedDispatcherOwner
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
@@ -43,6 +45,7 @@ import org.signal.core.ui.compose.Buttons
|
||||
import org.signal.core.ui.compose.ComposeDialogFragment
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.ui.rememberIsSplitPane
|
||||
import org.signal.core.util.BreakIteratorCompat
|
||||
import org.thoughtcrime.securesms.R
|
||||
@@ -68,6 +71,7 @@ class EditCallLinkNameDialogFragment : ComposeDialogFragment() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
dialog.window?.enableEdgeToEdge()
|
||||
return dialog
|
||||
}
|
||||
|
||||
@@ -143,7 +147,12 @@ private fun EditCallLinkNameScreen(
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val breakIterator = remember { BreakIteratorCompat.getInstance() }
|
||||
|
||||
Surface(modifier = Modifier.padding(paddingValues)) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.padding(paddingValues)
|
||||
.consumeWindowInsets(paddingValues)
|
||||
.imePadding()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
|
||||
@@ -8,8 +8,6 @@ package org.thoughtcrime.securesms.chats
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -124,8 +122,6 @@ private fun MessageDetailsEntry(route: MainNavigationDetailLocation.Chats.Messag
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(MaterialTheme.colorScheme.background)
|
||||
.statusBarsPadding()
|
||||
.navigationBarsPadding()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -12,7 +13,9 @@ import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
|
||||
import org.signal.core.ui.WindowExtensionsKt;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
|
||||
/**
|
||||
@@ -30,6 +33,15 @@ public abstract class FullScreenDialogFragment extends DialogFragment {
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
if (dialog.getWindow() != null) {
|
||||
WindowExtensionsKt.enableEdgeToEdge(dialog.getWindow());
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NonNull View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.full_screen_dialog_fragment, container, false);
|
||||
@@ -41,6 +53,8 @@ public abstract class FullScreenDialogFragment extends DialogFragment {
|
||||
}
|
||||
|
||||
toolbar.setNavigationOnClickListener(v -> onNavigateUp());
|
||||
|
||||
SystemWindowInsetsSetter.attach(view, getViewLifecycleOwner());
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
+65
-105
@@ -17,40 +17,37 @@
|
||||
package org.thoughtcrime.securesms.components;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.content.res.Configuration;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.widget.LinearLayoutCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.signal.core.util.ServiceUtil;
|
||||
import org.signal.core.util.Util;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* LinearLayout that, when a view container, will report back when it thinks a soft keyboard
|
||||
* has been opened and what its height would be.
|
||||
* has been opened and what its height would be. Driven by {@link WindowInsetsCompat.Type#ime()}
|
||||
* insets, so it requires an edge-to-edge host window (all activity and dialog windows in the app
|
||||
* are edge-to-edge). The reported height excludes the navigation bar, matching what a custom
|
||||
* keyboard sitting above a navigation-bar-padded container should be sized to.
|
||||
*/
|
||||
public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
private static final String TAG = Log.tag(KeyboardAwareLinearLayout.class);
|
||||
|
||||
private static final long KEYBOARD_DEBOUNCE = 150;
|
||||
|
||||
private final Rect rect = new Rect();
|
||||
private final Set<OnKeyboardHiddenListener> hiddenListeners = new HashSet<>();
|
||||
private final Set<OnKeyboardShownListener> shownListeners = new HashSet<>();
|
||||
private final DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
|
||||
private final int minKeyboardSize;
|
||||
private final int minCustomKeyboardSize;
|
||||
@@ -58,14 +55,14 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
private final int minCustomKeyboardTopMarginPortrait;
|
||||
private final int minCustomKeyboardTopMarginLandscape;
|
||||
private final int minCustomKeyboardTopMarginLandscapeBubble;
|
||||
private final int statusBarHeight;
|
||||
|
||||
private int viewInset;
|
||||
|
||||
private boolean keyboardOpen = false;
|
||||
private int rotation = 0;
|
||||
private boolean isBubble = false;
|
||||
private long openedAt = 0;
|
||||
private int lastKeyboardHeight;
|
||||
private boolean lastKeyboardVisible;
|
||||
|
||||
private InsetPaddingMode insetPaddingMode = InsetPaddingMode.NONE;
|
||||
|
||||
public KeyboardAwareLinearLayout(Context context) {
|
||||
this(context, null);
|
||||
@@ -83,48 +80,71 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
minCustomKeyboardTopMarginPortrait = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin_portrait);
|
||||
minCustomKeyboardTopMarginLandscape = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin_portrait);
|
||||
minCustomKeyboardTopMarginLandscapeBubble = getResources().getDimensionPixelSize(R.dimen.min_custom_keyboard_top_margin_landscape_bubble);
|
||||
statusBarHeight = ViewUtil.getStatusBarHeight(this);
|
||||
viewInset = getViewInset();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
updateRotation();
|
||||
updateKeyboardState();
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
ViewCompat.setOnApplyWindowInsetsListener(this, (view, insets) -> {
|
||||
Insets ime = insets.getInsets(WindowInsetsCompat.Type.ime());
|
||||
Insets nav = insets.getInsets(WindowInsetsCompat.Type.navigationBars());
|
||||
Insets bars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
|
||||
lastKeyboardHeight = Math.max(0, ime.bottom - nav.bottom);
|
||||
lastKeyboardVisible = insets.isVisible(WindowInsetsCompat.Type.ime());
|
||||
|
||||
switch (insetPaddingMode) {
|
||||
case NONE:
|
||||
break;
|
||||
case KEYBOARD:
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), lastKeyboardVisible ? lastKeyboardHeight : 0);
|
||||
break;
|
||||
case KEYBOARD_AND_NAVIGATION_BAR:
|
||||
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), Math.max(nav.bottom, ime.bottom));
|
||||
break;
|
||||
case SAFE_AREA:
|
||||
setPadding(bars.left, bars.top, bars.right, Math.max(bars.bottom, ime.bottom));
|
||||
break;
|
||||
}
|
||||
|
||||
updateKeyboardState();
|
||||
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
public void setIsBubble(boolean isBubble) {
|
||||
this.isBubble = isBubble;
|
||||
}
|
||||
|
||||
private void updateRotation() {
|
||||
int oldRotation = rotation;
|
||||
rotation = getDeviceRotation();
|
||||
if (oldRotation != rotation) {
|
||||
Log.i(TAG, "rotation changed");
|
||||
onKeyboardClose();
|
||||
}
|
||||
/**
|
||||
* Opt-in self-padding, replacing the window resize behavior these layouts relied on before the
|
||||
* host windows went edge-to-edge. [InsetPaddingMode.NONE] keeps the layout as a pure keyboard
|
||||
* event source (e.g. when a parent container already manages insets).
|
||||
*/
|
||||
public void setInsetPaddingMode(@NonNull InsetPaddingMode mode) {
|
||||
this.insetPaddingMode = mode;
|
||||
ViewCompat.requestApplyInsets(this);
|
||||
}
|
||||
|
||||
public enum InsetPaddingMode {
|
||||
/** Apply no padding; the layout only reports keyboard events. */
|
||||
NONE,
|
||||
/** Pad the bottom by the keyboard height above the navigation bar (use inside a container that already clears the navigation bar). */
|
||||
KEYBOARD,
|
||||
/** Pad the bottom by the keyboard or navigation bar, whichever is larger. */
|
||||
KEYBOARD_AND_NAVIGATION_BAR,
|
||||
/** Pad all sides by the system bars, and the bottom by the keyboard when it is taller. */
|
||||
SAFE_AREA
|
||||
}
|
||||
|
||||
private void updateKeyboardState() {
|
||||
if (viewInset == 0) viewInset = getViewInset();
|
||||
|
||||
getWindowVisibleDisplayFrame(rect);
|
||||
|
||||
final int availableHeight = getAvailableHeight();
|
||||
final int keyboardHeight = availableHeight - rect.bottom;
|
||||
|
||||
if (keyboardHeight > minKeyboardSize) {
|
||||
if (getKeyboardHeight() != keyboardHeight) {
|
||||
if (lastKeyboardVisible && lastKeyboardHeight > minKeyboardSize) {
|
||||
if (getKeyboardHeight() != lastKeyboardHeight) {
|
||||
if (isLandscape()) {
|
||||
setKeyboardLandscapeHeight(keyboardHeight);
|
||||
setKeyboardLandscapeHeight(lastKeyboardHeight);
|
||||
} else {
|
||||
setKeyboardPortraitHeight(keyboardHeight);
|
||||
setKeyboardPortraitHeight(lastKeyboardHeight);
|
||||
}
|
||||
}
|
||||
if (!keyboardOpen) {
|
||||
onKeyboardOpen(keyboardHeight);
|
||||
onKeyboardOpen(lastKeyboardHeight);
|
||||
}
|
||||
} else if (keyboardOpen) {
|
||||
onKeyboardClose();
|
||||
@@ -134,53 +154,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
rotation = getDeviceRotation();
|
||||
if (getRootWindowInsets() != null) {
|
||||
int bottomInset;
|
||||
WindowInsets windowInsets = getRootWindowInsets();
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
bottomInset = windowInsets.getInsets(WindowInsets.Type.navigationBars()).bottom;
|
||||
} else {
|
||||
bottomInset = windowInsets.getStableInsetBottom();
|
||||
}
|
||||
|
||||
if (bottomInset != 0 && (viewInset == 0 || viewInset == statusBarHeight)) {
|
||||
Log.i(TAG, "Updating view inset based on WindowInsets. viewInset: " + viewInset + " windowInset: " + bottomInset);
|
||||
viewInset = bottomInset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getViewInset() {
|
||||
try {
|
||||
Field attachInfoField = View.class.getDeclaredField("mAttachInfo");
|
||||
attachInfoField.setAccessible(true);
|
||||
Object attachInfo = attachInfoField.get(this);
|
||||
if (attachInfo != null) {
|
||||
Field stableInsetsField = attachInfo.getClass().getDeclaredField("mStableInsets");
|
||||
stableInsetsField.setAccessible(true);
|
||||
Rect insets = (Rect) stableInsetsField.get(attachInfo);
|
||||
if (insets != null) {
|
||||
return insets.bottom;
|
||||
}
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
// Do nothing
|
||||
}
|
||||
return statusBarHeight;
|
||||
}
|
||||
|
||||
private int getAvailableHeight() {
|
||||
final int availableHeight = this.getRootView().getHeight() - viewInset;
|
||||
final int availableWidth = this.getRootView().getWidth();
|
||||
|
||||
if (isLandscape() && availableHeight > availableWidth) {
|
||||
//noinspection SuspiciousNameCombination
|
||||
return availableWidth;
|
||||
}
|
||||
|
||||
return availableHeight;
|
||||
ViewCompat.requestApplyInsets(this);
|
||||
}
|
||||
|
||||
protected void onKeyboardOpen(int keyboardHeight) {
|
||||
@@ -213,21 +187,7 @@ public class KeyboardAwareLinearLayout extends LinearLayoutCompat {
|
||||
}
|
||||
|
||||
public boolean isLandscape() {
|
||||
int rotation = getDeviceRotation();
|
||||
return rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270;
|
||||
}
|
||||
|
||||
private int getDeviceRotation() {
|
||||
if (isInEditMode()) {
|
||||
return Surface.ROTATION_0;
|
||||
}
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 30) {
|
||||
getContext().getDisplay().getRealMetrics(displayMetrics);
|
||||
} else {
|
||||
ServiceUtil.getWindowManager(getContext()).getDefaultDisplay().getRealMetrics(displayMetrics);
|
||||
}
|
||||
return displayMetrics.widthPixels > displayMetrics.heightPixels ? Surface.ROTATION_90 : Surface.ROTATION_0;
|
||||
return getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
|
||||
}
|
||||
|
||||
private int getKeyboardLandscapeHeight() {
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.ViewGroup
|
||||
import android.view.WindowManager
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.thoughtcrime.securesms.R
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ abstract class KeyboardEntryDialogFragment(@LayoutRes contentLayoutId: Int) :
|
||||
}
|
||||
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE or WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
|
||||
dialog.window?.enableEdgeToEdge()
|
||||
|
||||
return dialog
|
||||
}
|
||||
@@ -47,6 +49,7 @@ abstract class KeyboardEntryDialogFragment(@LayoutRes contentLayoutId: Int) :
|
||||
|
||||
val view = super.onCreateView(inflater, container, savedInstanceState)
|
||||
return if (view is KeyboardAwareLinearLayout) {
|
||||
view.setInsetPaddingMode(KeyboardAwareLinearLayout.InsetPaddingMode.SAFE_AREA)
|
||||
view.addOnKeyboardShownListener(this)
|
||||
view.addOnKeyboardHiddenListener(this)
|
||||
view
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package org.thoughtcrime.securesms.components
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.activity.OnBackPressedCallback
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.ui.initializeScreenshotSecurity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
@@ -41,6 +43,12 @@ abstract class WrapperDialogFragment : DialogFragment(R.layout.fragment_containe
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
requireActivity().onBackPressedDispatcher.addCallback(
|
||||
viewLifecycleOwner,
|
||||
|
||||
+7
-19
@@ -14,8 +14,6 @@ import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.ConcatAdapter
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
@@ -88,15 +86,17 @@ abstract class DSLSettingsFragment(
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity windows are all edge-to-edge (enabled centrally in [org.thoughtcrime.securesms.BaseActivity]),
|
||||
* so the toolbar tint must extend behind the (transparent) status bar and the list must scroll clear of
|
||||
* the navigation bar. Skipped for dialog windows (not edge-to-edge) and for fragments embedded directly in
|
||||
* All host windows are edge-to-edge — activities centrally via [org.thoughtcrime.securesms.BaseActivity],
|
||||
* and the full-screen dialog hosts ([org.thoughtcrime.securesms.components.WrapperDialogFragment],
|
||||
* [org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment]) via their own
|
||||
* `enableEdgeToEdge` calls — so the toolbar tint must extend behind the (transparent) status bar and the
|
||||
* list must scroll clear of the navigation bar. Skipped only for fragments embedded directly in
|
||||
* [MainActivity]'s Compose scaffolding, which insets those containers itself — except the
|
||||
* conversation-settings detail entry ([ConversationSettingsNavHostFragment]), which leaves insets to these
|
||||
* fragments so the toolbar scroll tint can reach behind the status bar.
|
||||
*/
|
||||
private fun applyEdgeToEdgeInsets() {
|
||||
if (isDialogHosted() || isInsetByMainActivityHost()) {
|
||||
if (isInsetByMainActivityHost()) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -111,17 +111,6 @@ abstract class DSLSettingsFragment(
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDialogHosted(): Boolean {
|
||||
var fragment: Fragment? = this
|
||||
while (fragment != null) {
|
||||
if (fragment is DialogFragment && fragment.showsDialog) {
|
||||
return true
|
||||
}
|
||||
fragment = fragment.parentFragment
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isInsetByMainActivityHost(): Boolean {
|
||||
if (activity !is MainActivity) {
|
||||
return false
|
||||
@@ -137,8 +126,7 @@ abstract class DSLSettingsFragment(
|
||||
return Material3OnScrollHelper(
|
||||
activity = requireActivity(),
|
||||
views = listOf(toolbar),
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
setStatusBarColor = {}
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -114,9 +114,9 @@ class DonateToSignalFragment :
|
||||
}
|
||||
|
||||
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper {
|
||||
return object : Material3OnScrollHelper(activity = requireActivity(), views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner, setStatusBarColor = {}) {
|
||||
override val activeColorSet: ColorSet = ColorSet(R.color.transparent, CoreUiR.color.signal_colorBackground)
|
||||
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, CoreUiR.color.signal_colorBackground)
|
||||
return object : Material3OnScrollHelper(activity = requireActivity(), views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner) {
|
||||
override val activeColorSet: ColorSet = ColorSet(R.color.transparent)
|
||||
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.paypal
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.graphics.Bitmap
|
||||
import android.os.Bundle
|
||||
@@ -15,12 +16,14 @@ import androidx.fragment.app.setFragmentResult
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ViewBinderDelegate
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.PayPalRepository
|
||||
import org.thoughtcrime.securesms.components.settings.app.subscription.donate.DonationWebViewOnBackPressedCallback
|
||||
import org.thoughtcrime.securesms.databinding.DonationWebviewFragmentBinding
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
/**
|
||||
@@ -49,8 +52,16 @@ class PayPalConfirmationDialogFragment : DialogFragment(R.layout.donation_webvie
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
SystemWindowInsetsSetter.attach(view, viewLifecycleOwner)
|
||||
|
||||
val client = PayPalWebClient()
|
||||
viewLifecycleOwner.lifecycle.addObserver(client)
|
||||
binding.webView.webViewClient = client
|
||||
|
||||
+10
@@ -1,6 +1,7 @@
|
||||
package org.thoughtcrime.securesms.components.settings.app.subscription.donate.stripe
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Dialog
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.graphics.Bitmap
|
||||
@@ -24,6 +25,7 @@ import com.google.android.material.button.MaterialButton
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.signal.donations.StripeIntentAccessor
|
||||
import org.thoughtcrime.securesms.R
|
||||
@@ -35,6 +37,7 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData
|
||||
import org.thoughtcrime.securesms.databinding.DonationWebviewFragmentBinding
|
||||
import org.thoughtcrime.securesms.util.Environment
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
/**
|
||||
@@ -64,9 +67,16 @@ class Stripe3DSDialogFragment : DialogFragment(R.layout.donation_webview_fragmen
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("SetJavaScriptEnabled", "SetTextI18n")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner)
|
||||
SystemWindowInsetsSetter.attach(view, viewLifecycleOwner)
|
||||
|
||||
dialog!!.window!!.setFlags(
|
||||
WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,
|
||||
|
||||
+4
@@ -9,9 +9,11 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
@@ -231,6 +233,8 @@ fun BankTransferDetailsContent(
|
||||
.fillMaxWidth()
|
||||
.fillMaxHeight()
|
||||
.padding(it)
|
||||
.consumeWindowInsets(it)
|
||||
.imePadding()
|
||||
) {
|
||||
val focusManager = LocalFocusManager.current
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
|
||||
+6
-1
@@ -9,8 +9,10 @@ import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
@@ -237,7 +239,10 @@ private fun IdealTransferDetailsContent(
|
||||
|
||||
Column(
|
||||
horizontalAlignment = CenterHorizontally,
|
||||
modifier = Modifier.padding(it)
|
||||
modifier = Modifier
|
||||
.padding(it)
|
||||
.consumeWindowInsets(it)
|
||||
.imePadding()
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
|
||||
+3
-3
@@ -137,9 +137,9 @@ class ManageDonationsFragment :
|
||||
}
|
||||
|
||||
override fun getMaterial3OnScrollHelper(toolbar: Toolbar?): Material3OnScrollHelper {
|
||||
return object : Material3OnScrollHelper(activity = requireActivity(), views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner, setStatusBarColor = {}) {
|
||||
override val activeColorSet: ColorSet = ColorSet(R.color.transparent, CoreUiR.color.signal_colorBackground)
|
||||
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent, CoreUiR.color.signal_colorBackground)
|
||||
return object : Material3OnScrollHelper(activity = requireActivity(), views = listOf(toolbar!!), lifecycleOwner = viewLifecycleOwner) {
|
||||
override val activeColorSet: ColorSet = ColorSet(R.color.transparent)
|
||||
override val inactiveColorSet: ColorSet = ColorSet(R.color.transparent)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-4
@@ -272,12 +272,10 @@ class ConversationSettingsFragment :
|
||||
return object : Material3OnScrollHelper(
|
||||
activity = requireActivity(),
|
||||
views = listOf(toolbar!!),
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
setStatusBarColor = {}
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
) {
|
||||
override val inactiveColorSet = ColorSet(
|
||||
toolbarColorRes = CoreUiR.color.signal_colorBackground_0,
|
||||
statusBarColorRes = CoreUiR.color.signal_colorBackground
|
||||
toolbarColorRes = CoreUiR.color.signal_colorBackground_0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.conversation.clicklisteners
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
@@ -48,6 +49,7 @@ import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.core.ui.compose.horizontalGutters
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.avatar.AvatarImage
|
||||
@@ -88,6 +90,12 @@ class PollVotesFragment : ComposeDialogFragment(), RecipientBottomSheetDialogFra
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DialogContent() {
|
||||
val state by viewModel.state.collectAsStateWithLifecycle()
|
||||
|
||||
+3
-1
@@ -203,7 +203,9 @@ class MultiselectForwardFragment :
|
||||
isSplitPane = isSplitPane,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.navigationBarsPadding()
|
||||
// Bottom-sheet hosts already clear the navigation bar via BottomSheetBehavior's
|
||||
// edge-to-edge padding; padding again here would double up.
|
||||
.then(if (args.isWrappedInBottomSheet) Modifier else Modifier.navigationBarsPadding())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.conversation.mutiselect.forward
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -7,6 +8,7 @@ import android.view.ViewGroup
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
@@ -19,6 +21,12 @@ class MultiselectForwardFullScreenDialogFragment : DialogFragment(), Multiselect
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFinishForwardAction() {
|
||||
findListener<Callback>()?.onFinishForwardAction()
|
||||
}
|
||||
|
||||
+1
-4
@@ -57,7 +57,6 @@ import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.app.ActivityOptionsCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.content.pm.ShortcutManagerCompat
|
||||
import androidx.core.os.bundleOf
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.doOnPreDraw
|
||||
@@ -5178,9 +5177,7 @@ class ConversationFragment :
|
||||
|
||||
private object MediaKeyboardFragmentCreator : InputAwareConstraintLayout.FragmentCreator {
|
||||
override val id: Int = MEDIA_KEYBOARD_FRAGMENT_CREATOR_ID
|
||||
override fun create(): Fragment = KeyboardPagerFragment().apply {
|
||||
arguments = bundleOf(KeyboardPagerFragment.ARG_SET_NAV_COLOR to false)
|
||||
}
|
||||
override fun create(): Fragment = KeyboardPagerFragment()
|
||||
}
|
||||
|
||||
private inner class KeyboardEvents :
|
||||
|
||||
+1
-2
@@ -22,8 +22,7 @@ class ConversationToolbarOnScrollHelper(
|
||||
) : Material3OnScrollHelper(
|
||||
activity = activity,
|
||||
views = listOf(toolbarBackground),
|
||||
lifecycleOwner = lifecycleOwner,
|
||||
setStatusBarColor = {}
|
||||
lifecycleOwner = lifecycleOwner
|
||||
) {
|
||||
override val activeColorSet: ColorSet
|
||||
get() = when {
|
||||
|
||||
@@ -63,6 +63,7 @@ import org.signal.core.ui.compose.list.ReorderListEvent
|
||||
import org.signal.core.ui.compose.list.ReorderableItem
|
||||
import org.signal.core.ui.compose.list.rememberReorderableListState
|
||||
import org.signal.core.ui.compose.list.reorderableList
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.polls.Poll
|
||||
@@ -97,6 +98,7 @@ class CreatePollFragment : ComposeDialogFragment() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
|
||||
dialog.window?.enableEdgeToEdge()
|
||||
return dialog
|
||||
}
|
||||
|
||||
|
||||
@@ -4,11 +4,8 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.Window
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import org.signal.core.ui.util.ThemeUtil
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.InputAwareConstraintLayout
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
@@ -18,17 +15,12 @@ import org.thoughtcrime.securesms.keyboard.sticker.StickerKeyboardPageFragment
|
||||
import org.thoughtcrime.securesms.util.ThemedFragment.themeResId
|
||||
import org.thoughtcrime.securesms.util.ThemedFragment.themedInflate
|
||||
import org.thoughtcrime.securesms.util.ThemedFragment.withTheme
|
||||
import org.thoughtcrime.securesms.util.WindowUtil
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragment {
|
||||
|
||||
companion object {
|
||||
val ARG_SET_NAV_COLOR = "args.setNavColor"
|
||||
}
|
||||
|
||||
private lateinit var emojiButton: View
|
||||
private lateinit var stickerButton: View
|
||||
private lateinit var gifButton: View
|
||||
@@ -37,9 +29,6 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme
|
||||
private val fragments: MutableMap<KClass<*>, Fragment> = mutableMapOf()
|
||||
private var currentFragment: Fragment? = null
|
||||
|
||||
private val shouldSetNavColor: Boolean
|
||||
get() = arguments?.getBoolean(ARG_SET_NAV_COLOR) ?: true
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return themedInflate(R.layout.keyboard_pager_fragment, inflater, container)
|
||||
}
|
||||
@@ -61,20 +50,6 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme
|
||||
emojiButton.setOnClickListener { viewModel.switchToPage(KeyboardPage.EMOJI) }
|
||||
stickerButton.setOnClickListener { viewModel.switchToPage(KeyboardPage.STICKER) }
|
||||
gifButton.setOnClickListener { viewModel.switchToPage(KeyboardPage.GIF) }
|
||||
|
||||
onHiddenChanged(false)
|
||||
}
|
||||
|
||||
override fun onHiddenChanged(hidden: Boolean) {
|
||||
if (shouldSetNavColor) {
|
||||
getWindow()?.let { window ->
|
||||
if (hidden) {
|
||||
WindowUtil.setNavigationBarColor(requireContext(), window, ThemeUtil.getThemedColor(requireContext(), android.R.attr.navigationBarColor))
|
||||
} else {
|
||||
WindowUtil.setNavigationBarColor(requireContext(), window, ThemeUtil.getThemedColor(requireContext(), R.attr.mediaKeyboardBottomBarBackgroundColor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@@ -83,19 +58,6 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme
|
||||
viewModel.page().value?.let(this::onPageSelected)
|
||||
}
|
||||
|
||||
private fun getWindow(): Window? {
|
||||
var parent: Fragment? = parentFragment
|
||||
while (parent != null) {
|
||||
if (parent is DialogFragment) {
|
||||
return parent.dialog?.window
|
||||
}
|
||||
|
||||
parent = parent.parentFragment
|
||||
}
|
||||
|
||||
return activity?.window
|
||||
}
|
||||
|
||||
private fun onPageSelected(page: KeyboardPage) {
|
||||
emojiButton.isSelected = page == KeyboardPage.EMOJI
|
||||
stickerButton.isSelected = page == KeyboardPage.STICKER
|
||||
@@ -143,8 +105,6 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme
|
||||
override fun show() {
|
||||
findListener<MediaKeyboard.MediaKeyboardListener>()?.onShown()
|
||||
if (isAdded && view != null) {
|
||||
onHiddenChanged(false)
|
||||
|
||||
viewModel.page().value?.let(this::onPageSelected)
|
||||
}
|
||||
}
|
||||
@@ -152,8 +112,6 @@ class KeyboardPagerFragment : Fragment(), InputAwareConstraintLayout.InputFragme
|
||||
override fun hide() {
|
||||
findListener<MediaKeyboard.MediaKeyboardListener>()?.onHidden()
|
||||
if (isAdded && view != null) {
|
||||
onHiddenChanged(true)
|
||||
|
||||
val transaction = childFragmentManager.beginTransaction()
|
||||
fragments.values.forEach { transaction.remove(it) }
|
||||
transaction.commitAllowingStateLoss()
|
||||
|
||||
+16
@@ -1,16 +1,20 @@
|
||||
package org.thoughtcrime.securesms.keyboard.sticker
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.annotation.Px
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.bumptech.glide.Glide
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.keyboard.emoji.KeyboardPageSearchView
|
||||
import org.thoughtcrime.securesms.stickers.StickerEventListener
|
||||
@@ -37,12 +41,24 @@ class StickerSearchDialogFragment : DialogFragment(), KeyboardStickerListAdapter
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_Animated_Bottom)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.sticker_search_dialog_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
ViewCompat.setOnApplyWindowInsetsListener(view) { v, insets ->
|
||||
val safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime())
|
||||
v.setPadding(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom)
|
||||
insets
|
||||
}
|
||||
|
||||
search = view.findViewById(R.id.sticker_search_text)
|
||||
list = view.findViewById(R.id.sticker_search_list)
|
||||
noResults = view.findViewById(R.id.sticker_search_no_results)
|
||||
|
||||
@@ -16,12 +16,15 @@ import android.os.Bundle;
|
||||
import android.view.View;
|
||||
import android.view.animation.OvershootInterpolator;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.gms.maps.CameraUpdateFactory;
|
||||
@@ -73,6 +76,7 @@ public final class PlacePickerActivity extends AppCompatActivity {
|
||||
private LatLng currentLocation = new LatLng(0, 0);
|
||||
private AddressLookup addressLookup;
|
||||
private GoogleMap googleMap;
|
||||
private Insets systemBarInsets;
|
||||
|
||||
public static void startActivityForResultAtCurrentLocation(@NonNull Fragment fragment, int requestCode, @ColorInt int chatColor) {
|
||||
fragment.startActivityForResult(new Intent(fragment.requireActivity(), PlacePickerActivity.class).putExtra(KEY_CHAT_COLOR, chatColor), requestCode);
|
||||
@@ -85,15 +89,23 @@ public final class PlacePickerActivity extends AppCompatActivity {
|
||||
@SuppressLint("MissingInflatedId")
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
dynamicTheme.onCreate(this);
|
||||
|
||||
|
||||
setContentView(R.layout.activity_place_picker);
|
||||
|
||||
bottomSheet = findViewById(R.id.bottom_sheet);
|
||||
View markerImage = findViewById(R.id.marker_image_view);
|
||||
View fab = findViewById(R.id.place_chosen_button);
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (view, insets) -> {
|
||||
systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());
|
||||
bottomSheet.setPadding(systemBarInsets.left, 0, systemBarInsets.right, systemBarInsets.bottom);
|
||||
applyMapPadding();
|
||||
return insets;
|
||||
});
|
||||
|
||||
ViewCompat.setBackgroundTintList(fab, ColorStateList.valueOf(getIntent().getIntExtra(KEY_CHAT_COLOR, Color.RED)));
|
||||
fab.setOnClickListener(v -> finishWithAddress());
|
||||
|
||||
@@ -167,9 +179,16 @@ public final class PlacePickerActivity extends AppCompatActivity {
|
||||
private void setMap(GoogleMap googleMap) {
|
||||
this.googleMap = googleMap;
|
||||
|
||||
applyMapPadding();
|
||||
moveMapToInitialIfPossible();
|
||||
}
|
||||
|
||||
private void applyMapPadding() {
|
||||
if (googleMap != null && systemBarInsets != null) {
|
||||
googleMap.setPadding(systemBarInsets.left, systemBarInsets.top, systemBarInsets.right, systemBarInsets.bottom);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveMapToInitialIfPossible() {
|
||||
if (initialLocation != null && googleMap != null) {
|
||||
Log.d(TAG, "Moving map to initial location");
|
||||
|
||||
@@ -5,8 +5,8 @@ import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@@ -63,12 +63,9 @@ public class AvatarSelectionActivity extends AppCompatActivity implements Camera
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this);
|
||||
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()) {
|
||||
|
||||
+1
-2
@@ -115,8 +115,7 @@ class MediaGalleryFragment : Fragment(R.layout.v2_media_gallery_fragment) {
|
||||
Material3OnScrollHelper(
|
||||
activity = requireActivity(),
|
||||
views = listOf(binding.mediaGalleryToolbar, binding.mediaGalleryStatusBarBackground),
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
setStatusBarColor = {}
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
).attach(binding.mediaGalleryGrid)
|
||||
|
||||
if (callbacks.isCameraEnabled()) {
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet.forOutgoingMessageRecord
|
||||
import org.thoughtcrime.securesms.stickers.StickerLocator
|
||||
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
|
||||
class MessageDetailsFragment : Fragment(), MessageDetailsAdapter.Callbacks {
|
||||
@@ -70,6 +71,8 @@ class MessageDetailsFragment : Fragment(), MessageDetailsAdapter.Callbacks {
|
||||
toolbar.setTitle(R.string.AndroidManifest__message_details)
|
||||
toolbar.setNavigationOnClickListener { requireActivity().onBackPressedDispatcher.onBackPressed() }
|
||||
|
||||
SystemWindowInsetsSetter.attach(view, viewLifecycleOwner)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,14 @@ package org.thoughtcrime.securesms.pin;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import org.thoughtcrime.securesms.MainActivity;
|
||||
import org.thoughtcrime.securesms.PassphraseRequiredActivity;
|
||||
@@ -19,9 +24,16 @@ public final class PinRestoreActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this);
|
||||
dynamicTheme.onCreate(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.pin_restore_activity);
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (view, insets) -> {
|
||||
Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime());
|
||||
view.setPadding(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.thoughtcrime.securesms.profiles.username
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Column
|
||||
@@ -32,6 +33,7 @@ import org.signal.core.ui.compose.DayNightPreviews
|
||||
import org.signal.core.ui.compose.Previews
|
||||
import org.signal.core.ui.compose.Scaffolds
|
||||
import org.signal.core.ui.compose.SignalIcons
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.profiles.manage.EditProfileActivity
|
||||
import org.signal.core.ui.R as CoreUiR
|
||||
@@ -48,6 +50,12 @@ class NewWaysToConnectDialogFragment : ComposeDialogFragment() {
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
override fun DialogContent() {
|
||||
NewWaysToConnectDialogContent(
|
||||
|
||||
-13
@@ -1,6 +1,5 @@
|
||||
package org.thoughtcrime.securesms.reactions;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
@@ -11,7 +10,6 @@ import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
@@ -23,7 +21,6 @@ import com.google.android.material.tabs.TabLayoutMediator;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiImageView;
|
||||
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||
import org.thoughtcrime.securesms.util.FullscreenHelper;
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable;
|
||||
import org.thoughtcrime.securesms.util.WindowUtil;
|
||||
|
||||
@@ -81,16 +78,6 @@ public final class ReactionsBottomSheetDialogFragment extends BottomSheetDialogF
|
||||
super.onCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
|
||||
FullscreenHelper.showSystemUI(dialog.getWindow());
|
||||
WindowUtil.setNavigationBarColor(requireContext(), dialog.getWindow(), ContextCompat.getColor(requireContext(), org.signal.core.ui.R.color.signal_colorSurface1));
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
|
||||
+13
@@ -1,5 +1,6 @@
|
||||
package org.thoughtcrime.securesms.recipients.ui.sharablegrouplink.qr;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Color;
|
||||
@@ -19,6 +20,7 @@ import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.signal.core.ui.BottomSheetUtil;
|
||||
import org.signal.core.ui.WindowExtensionsKt;
|
||||
import org.signal.core.ui.util.ThemeUtil;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -26,6 +28,7 @@ import org.thoughtcrime.securesms.components.qr.QrView;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.groups.GroupId;
|
||||
import org.thoughtcrime.securesms.qr.QrCodeUtil;
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
@@ -59,6 +62,15 @@ public class GroupLinkShareQrDialogFragment extends DialogFragment {
|
||||
: R.style.TextSecure_LightTheme);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
if (dialog.getWindow() != null) {
|
||||
WindowExtensionsKt.enableEdgeToEdge(dialog.getWindow());
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable View onCreateView(@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@@ -69,6 +81,7 @@ public class GroupLinkShareQrDialogFragment extends DialogFragment {
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
SystemWindowInsetsSetter.attach(view, getViewLifecycleOwner());
|
||||
initializeViewModel();
|
||||
initializeViews(view);
|
||||
}
|
||||
|
||||
+11
@@ -5,10 +5,14 @@ import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import org.signal.core.util.concurrent.SignalExecutors;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
@@ -36,8 +40,15 @@ public final class ImageEditorStickerSelectActivity extends AppCompatActivity im
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.scribble_select_new_sticker_activity);
|
||||
|
||||
ViewCompat.setOnApplyWindowInsetsListener(findViewById(android.R.id.content), (view, insets) -> {
|
||||
Insets safeArea = insets.getInsets(WindowInsetsCompat.Type.systemBars() | WindowInsetsCompat.Type.ime());
|
||||
view.setPadding(safeArea.left, safeArea.top, safeArea.right, safeArea.bottom);
|
||||
return insets;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+8
-9
@@ -1,12 +1,13 @@
|
||||
package org.thoughtcrime.securesms.stories.settings.create
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.stories.settings.select.BaseStoryRecipientSelectionFragment
|
||||
import org.thoughtcrime.securesms.util.WindowUtil
|
||||
|
||||
class CreateStoryFlowDialogFragment : DialogFragment(R.layout.create_story_flow_dialog_fragment), BaseStoryRecipientSelectionFragment.Callback, CreateStoryWithViewersFragment.Callback {
|
||||
|
||||
@@ -15,6 +16,12 @@ class CreateStoryFlowDialogFragment : DialogFragment(R.layout.create_story_flow_
|
||||
setStyle(STYLE_NO_FRAME, R.style.Signal_DayNight_Dialog_FullScreen)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
override fun exitFlow() {
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
@@ -28,12 +35,4 @@ class CreateStoryFlowDialogFragment : DialogFragment(R.layout.create_story_flow_
|
||||
)
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
override fun setStatusBarColor(color: Int) {
|
||||
WindowUtil.setStatusBarColor(requireDialog().window!!, color)
|
||||
}
|
||||
|
||||
override fun getStatusBarColor(): Int {
|
||||
return WindowUtil.getStatusBarColor(requireDialog().window!!)
|
||||
}
|
||||
}
|
||||
|
||||
+3
-6
@@ -2,8 +2,8 @@ package org.thoughtcrime.securesms.stories.settings.create
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
@@ -16,11 +16,11 @@ import org.thoughtcrime.securesms.components.settings.configure
|
||||
import org.thoughtcrime.securesms.databinding.StoriesCreateWithRecipientsFragmentBinding
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.Material3OnScrollHelper
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
|
||||
import org.thoughtcrime.securesms.util.ViewUtil
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
import org.thoughtcrime.securesms.util.fragments.requireListener
|
||||
import org.thoughtcrime.securesms.util.viewholders.RecipientMappingModel
|
||||
import org.thoughtcrime.securesms.util.viewholders.RecipientViewHolder
|
||||
|
||||
@@ -80,11 +80,10 @@ class CreateStoryWithViewersFragment : DSLSettingsFragment(
|
||||
|
||||
Material3OnScrollHelper(
|
||||
activity = requireActivity(),
|
||||
setStatusBarColor = { requireListener<Callback>().setStatusBarColor(it) },
|
||||
getStatusBarColor = { requireListener<Callback>().getStatusBarColor() },
|
||||
views = listOf(binding.toolbar),
|
||||
lifecycleOwner = viewLifecycleOwner
|
||||
).attach(binding.appBarLayout)
|
||||
SystemWindowInsetsSetter.attach(binding.create, viewLifecycleOwner, WindowInsetsCompat.Type.navigationBars(), SystemWindowInsetsSetter.ApplyMode.MARGIN)
|
||||
ViewUtil.focusAndShowKeyboard(binding.nameField.editText)
|
||||
}
|
||||
|
||||
@@ -142,8 +141,6 @@ class CreateStoryWithViewersFragment : DSLSettingsFragment(
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun setStatusBarColor(@ColorInt color: Int)
|
||||
fun getStatusBarColor(): Int
|
||||
fun onDone(recipientId: RecipientId)
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -2,8 +2,11 @@ package org.thoughtcrime.securesms.stories.settings.select
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.EditText
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.viewModels
|
||||
@@ -20,6 +23,7 @@ import org.thoughtcrime.securesms.contacts.selection.ContactSelectionArguments
|
||||
import org.thoughtcrime.securesms.database.model.DistributionListId
|
||||
import org.thoughtcrime.securesms.groups.SelectionLimits
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.util.SystemWindowInsetsSetter
|
||||
import org.thoughtcrime.securesms.util.fragments.findListener
|
||||
import java.util.Optional
|
||||
import java.util.function.Consumer
|
||||
@@ -54,6 +58,11 @@ abstract class BaseStoryRecipientSelectionFragment : Fragment(R.layout.stories_b
|
||||
|
||||
toolbar.setTitle(toolbarTitleId)
|
||||
|
||||
toolbar.updateLayoutParams { height = ViewGroup.LayoutParams.WRAP_CONTENT }
|
||||
SystemWindowInsetsSetter.attach(toolbar, viewLifecycleOwner, WindowInsetsCompat.Type.statusBars())
|
||||
SystemWindowInsetsSetter.attach(view.findViewById(R.id.contacts_container), viewLifecycleOwner, WindowInsetsCompat.Type.navigationBars())
|
||||
SystemWindowInsetsSetter.attach(actionButton, viewLifecycleOwner, WindowInsetsCompat.Type.navigationBars(), SystemWindowInsetsSetter.ApplyMode.MARGIN)
|
||||
|
||||
lifecycleDisposable.bindTo(viewLifecycleOwner)
|
||||
|
||||
actionButton.setText(actionButtonLabel)
|
||||
|
||||
+8
-6
@@ -3,6 +3,7 @@ package org.thoughtcrime.securesms.stories.viewer.first
|
||||
import android.app.Dialog
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.ColorDrawable
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.view.WindowManager
|
||||
@@ -10,6 +11,7 @@ import androidx.core.app.ActivityCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.viewModels
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||
@@ -34,13 +36,13 @@ class StoryFirstTimeNavigationFragment : DialogFragment(R.layout.story_viewer_fi
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val dialog = super.onCreateDialog(savedInstanceState)
|
||||
dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
|
||||
dialog.window!!.enableEdgeToEdge()
|
||||
|
||||
dialog.window!!.addFlags(
|
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION or
|
||||
WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS or
|
||||
WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or
|
||||
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= 28) {
|
||||
dialog.window!!.attributes = dialog.window!!.attributes.apply {
|
||||
layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
|
||||
}
|
||||
}
|
||||
return dialog
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ import org.signal.core.util.dp
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.ComposeText
|
||||
import org.thoughtcrime.securesms.components.InputAwareLayout
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout
|
||||
import org.thoughtcrime.securesms.components.emoji.Emoji
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiPageModel
|
||||
@@ -170,6 +171,10 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||
return Input(trimmedText, mentions, bodyRanges)
|
||||
}
|
||||
|
||||
fun setInsetPaddingMode(mode: KeyboardAwareLinearLayout.InsetPaddingMode) {
|
||||
inputAwareLayout.setInsetPaddingMode(mode)
|
||||
}
|
||||
|
||||
fun openEmojiSearch() {
|
||||
emojiDrawer.onOpenEmojiSearch()
|
||||
}
|
||||
|
||||
+3
@@ -24,6 +24,7 @@ import org.signal.core.util.concurrent.SignalExecutors
|
||||
import org.signal.core.util.getParcelableCompat
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.KeyboardAwareLinearLayout
|
||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||
@@ -172,6 +173,8 @@ class StoryGroupReplyFragment :
|
||||
|
||||
composer.callback = this
|
||||
composer.hint = getString(R.string.StoryViewerPageFragment__reply_to_group)
|
||||
// The hosting bottom sheet already clears the navigation bar; the composer only needs to ride above the keyboard.
|
||||
composer.setInsetPaddingMode(KeyboardAwareLinearLayout.InsetPaddingMode.KEYBOARD)
|
||||
|
||||
onPageSelected(findListener<StoryViewsAndRepliesPagerParent>()?.selectedChild ?: StoryViewsAndRepliesPagerParent.Child.REPLIES)
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@ import org.signal.core.ui.R as CoreUiR
|
||||
*/
|
||||
open class Material3OnScrollHelper(
|
||||
private val activity: FragmentActivity,
|
||||
private val setStatusBarColor: (Int) -> Unit = { WindowUtil.setStatusBarColor(activity.window, it) },
|
||||
getStatusBarColor: () -> Int = { WindowUtil.getStatusBarColor(activity.window) },
|
||||
private val setChatFolderColor: (Int) -> Unit = {},
|
||||
private val onSetToolbarColor: (Int) -> Unit = {},
|
||||
private val views: List<View> = emptyList(),
|
||||
@@ -37,23 +35,19 @@ open class Material3OnScrollHelper(
|
||||
*/
|
||||
@JvmStatic
|
||||
fun create(activity: FragmentActivity, toolbar: View): Material3OnScrollHelper {
|
||||
return Material3OnScrollHelper(activity = activity, views = listOf(toolbar), lifecycleOwner = activity, setStatusBarColor = {})
|
||||
return Material3OnScrollHelper(activity = activity, views = listOf(toolbar), lifecycleOwner = activity)
|
||||
}
|
||||
}
|
||||
|
||||
open val activeColorSet: ColorSet = ColorSet(
|
||||
toolbarColorRes = CoreUiR.color.signal_colorSurface2,
|
||||
statusBarColorRes = CoreUiR.color.signal_colorSurface2,
|
||||
chatFolderColorRes = CoreUiR.color.signal_colorBackground
|
||||
)
|
||||
open val inactiveColorSet: ColorSet = ColorSet(
|
||||
toolbarColorRes = CoreUiR.color.signal_colorBackground,
|
||||
statusBarColorRes = CoreUiR.color.signal_colorBackground,
|
||||
chatFolderColorRes = CoreUiR.color.signal_colorSurface2
|
||||
)
|
||||
|
||||
protected var previousStatusBarColor: Int = getStatusBarColor()
|
||||
|
||||
private var animator: ValueAnimator? = null
|
||||
private var active: Boolean? = null
|
||||
|
||||
@@ -65,7 +59,6 @@ open class Material3OnScrollHelper(
|
||||
|
||||
override fun onDestroy(owner: LifecycleOwner) {
|
||||
animator?.cancel()
|
||||
setStatusBarColor(previousStatusBarColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -105,7 +98,6 @@ open class Material3OnScrollHelper(
|
||||
animator?.cancel()
|
||||
val colorSet = if (active == true) activeColorSet else inactiveColorSet
|
||||
setToolbarColor(ContextCompat.getColor(activity, colorSet.toolbarColorRes))
|
||||
setStatusBarColor(ContextCompat.getColor(activity, colorSet.statusBarColorRes))
|
||||
setChatFolderColor(ContextCompat.getColor(activity, colorSet.chatFolderColorRes))
|
||||
}
|
||||
|
||||
@@ -129,8 +121,6 @@ open class Material3OnScrollHelper(
|
||||
if (hadActiveState) {
|
||||
val startToolbarColor = ContextCompat.getColor(activity, startColorSet.toolbarColorRes)
|
||||
val endToolbarColor = ContextCompat.getColor(activity, endColorSet.toolbarColorRes)
|
||||
val startStatusBarColor = ContextCompat.getColor(activity, startColorSet.statusBarColorRes)
|
||||
val endStatusBarColor = ContextCompat.getColor(activity, endColorSet.statusBarColorRes)
|
||||
val startChatFolderColor = ContextCompat.getColor(activity, startColorSet.chatFolderColorRes)
|
||||
val endChatFolderColor = ContextCompat.getColor(activity, endColorSet.chatFolderColorRes)
|
||||
|
||||
@@ -138,7 +128,6 @@ open class Material3OnScrollHelper(
|
||||
duration = 200
|
||||
addUpdateListener {
|
||||
setToolbarColor(ArgbEvaluatorCompat.getInstance().evaluate(it.animatedFraction, startToolbarColor, endToolbarColor))
|
||||
setStatusBarColor(ArgbEvaluatorCompat.getInstance().evaluate(it.animatedFraction, startStatusBarColor, endStatusBarColor))
|
||||
setChatFolderColor(ArgbEvaluatorCompat.getInstance().evaluate(it.animatedFraction, startChatFolderColor, endChatFolderColor))
|
||||
}
|
||||
start()
|
||||
@@ -174,10 +163,6 @@ open class Material3OnScrollHelper(
|
||||
*/
|
||||
data class ColorSet(
|
||||
@ColorRes val toolbarColorRes: Int,
|
||||
@ColorRes val statusBarColorRes: Int,
|
||||
@ColorRes val chatFolderColorRes: Int
|
||||
) {
|
||||
constructor(@ColorRes color: Int) : this(color, color)
|
||||
constructor(@ColorRes toolbarColorRes: Int, @ColorRes statusBarColorRes: Int) : this(toolbarColorRes, statusBarColorRes, toolbarColorRes)
|
||||
}
|
||||
@ColorRes val chatFolderColorRes: Int = toolbarColorRes
|
||||
)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.Window;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.view.WindowInsetsControllerCompat;
|
||||
|
||||
@@ -41,18 +40,6 @@ public final class WindowUtil {
|
||||
controller(window).setAppearanceLightNavigationBars(true);
|
||||
}
|
||||
|
||||
public static void setNavigationBarColor(@NonNull Activity activity, @ColorInt int color) {
|
||||
setNavigationBarColor(activity, activity.getWindow(), color);
|
||||
}
|
||||
|
||||
public static void setNavigationBarColor(@NonNull Context context, @NonNull Window window, @ColorInt int color) {
|
||||
if (Build.VERSION.SDK_INT < 27) {
|
||||
window.setNavigationBarColor(ThemeUtil.getThemedColor(context, android.R.attr.navigationBarColor));
|
||||
} else {
|
||||
window.setNavigationBarColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setLightStatusBarFromTheme(@NonNull Activity activity) {
|
||||
final boolean isLightStatusBar = ThemeUtil.getThemedBoolean(activity, android.R.attr.windowLightStatusBar);
|
||||
|
||||
@@ -68,14 +55,6 @@ public final class WindowUtil {
|
||||
controller(window).setAppearanceLightStatusBars(true);
|
||||
}
|
||||
|
||||
public static void setStatusBarColor(@NonNull Window window, @ColorInt int color) {
|
||||
window.setStatusBarColor(color);
|
||||
}
|
||||
|
||||
public static int getStatusBarColor(@NonNull Window window) {
|
||||
return window.getStatusBarColor();
|
||||
}
|
||||
|
||||
private static @NonNull WindowInsetsControllerCompat controller(@NonNull Window window) {
|
||||
return new WindowInsetsControllerCompat(window, window.getDecorView());
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.core.view.OneShotPreDrawListener
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import org.signal.core.util.concurrent.LifecycleDisposable
|
||||
@@ -39,9 +38,8 @@ class VerifyScanFragment : Fragment() {
|
||||
cameraScrim = view.findViewById(R.id.camera_scrim)
|
||||
cameraMarks = view.findViewById(R.id.camera_marks)
|
||||
|
||||
if (!isDialogHosted()) {
|
||||
SystemWindowInsetsSetter.attach(view.findViewById<TextView>(R.id.information), viewLifecycleOwner, WindowInsetsCompat.Type.navigationBars(), SystemWindowInsetsSetter.ApplyMode.MARGIN)
|
||||
}
|
||||
SystemWindowInsetsSetter.attach(view.findViewById<TextView>(R.id.information), viewLifecycleOwner, WindowInsetsCompat.Type.navigationBars(), SystemWindowInsetsSetter.ApplyMode.MARGIN)
|
||||
|
||||
OneShotPreDrawListener.add(cameraScrim) {
|
||||
val width = cameraScrim.scrimWidth
|
||||
val height = cameraScrim.scrimHeight
|
||||
@@ -60,8 +58,4 @@ class VerifyScanFragment : Fragment() {
|
||||
findListener<ScanListener>()?.onQrDataFound(qrData)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isDialogHosted(): Boolean {
|
||||
return generateSequence<Fragment>(this) { it.parentFragment }.any { it is DialogFragment && it.showsDialog }
|
||||
}
|
||||
}
|
||||
|
||||
+2
-5
@@ -3,8 +3,8 @@ package org.thoughtcrime.securesms.wallpaper.crop;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import androidx.activity.EdgeToEdge;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
@@ -37,12 +37,9 @@ public final class WallpaperImageSelectionActivity extends AppCompatActivity
|
||||
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
EdgeToEdge.enable(this);
|
||||
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()
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<style name="TextSecure.LightTheme" parent="TextSecure.BaseLightTheme">
|
||||
<item name="android:statusBarColor">@color/core_grey_60</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkTheme" parent="@style/TextSecure.BaseDarkTheme">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkNoActionBar" parent="@style/TextSecure.BaseDarkNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:colorControlActivated">@color/core_ultramarine_light</item>
|
||||
</style>
|
||||
|
||||
@@ -23,41 +12,22 @@
|
||||
<item name="android:windowSharedElementExitTransition">@transition/change_transform</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightNoActionBar" parent="TextSecure.BaseLightNoActionBar">
|
||||
<item name="android:statusBarColor">@color/core_grey_60</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.FullScreenMedia" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightRegistrationTheme" parent="TextSecure.LightNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkRegistrationTheme" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.MediaPreview" parent="@style/TextSecure.BaseMediaPreview">
|
||||
<item name="android:navigationBarColor">@color/media_preview_bar_background</item>
|
||||
<item name="android:windowContentTransitions">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Signal.Light.BottomSheetDialog" parent="Theme.Material3.Light.BottomSheetDialog">
|
||||
<item name="android:navigationBarColor">@color/signal_colorSurface1</item>
|
||||
<item name="android:navigationBarColor">@color/signal_bottom_sheet_navigation_bar</item>
|
||||
<item name="enableEdgeToEdge">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Signal.BottomSheetDialog" parent="Theme.Material3.Dark.BottomSheetDialog">
|
||||
<item name="android:navigationBarColor">@color/signal_colorSurface1</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Signal.BottomSheetDialog.Fixed">
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/transparent</item>
|
||||
<item name="android:navigationBarColor">@color/signal_bottom_sheet_navigation_bar</item>
|
||||
<item name="enableEdgeToEdge">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightNoActionBar.ConversationSettings" parent="TextSecure.LightNoActionBar">
|
||||
|
||||
@@ -2,41 +2,31 @@
|
||||
<resources>
|
||||
<style name="TextSecure.LightTheme" parent="TextSecure.BaseLightTheme">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkTheme" parent="TextSecure.BaseDarkTheme">
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightRegistrationTheme" parent="TextSecure.LightNoActionBar">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkRegistrationTheme" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightNoActionBar" parent="TextSecure.BaseLightNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkNoActionBar" parent="TextSecure.BaseDarkNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Signal.BottomSheetDialog.Fixed">
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorSurface1</item>
|
||||
<item name="android:statusBarColor">@color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
</style>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Transparent on API 27+: Material's BottomSheetDialog only lays the sheet out edge-to-edge
|
||||
(and pads it for the navigation bar) when the window navigation bar color is non-opaque. -->
|
||||
<color name="bottom_sheet_navigation_bar_surface">@android:color/transparent</color>
|
||||
|
||||
</resources>
|
||||
@@ -3,43 +3,31 @@
|
||||
|
||||
<style name="TextSecure.LightTheme" parent="TextSecure.BaseLightTheme">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkTheme" parent="TextSecure.BaseDarkTheme">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightRegistrationTheme" parent="TextSecure.LightNoActionBar">
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkRegistrationTheme" parent="TextSecure.DarkNoActionBar">
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.LightNoActionBar" parent="TextSecure.BaseLightNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">true</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">true</item>
|
||||
</style>
|
||||
|
||||
<style name="TextSecure.DarkNoActionBar" parent="TextSecure.BaseDarkNoActionBar">
|
||||
<item name="android:statusBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
</style>
|
||||
|
||||
@@ -47,7 +35,8 @@
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:statusBarColor">@color/transparent</item>
|
||||
<item name="android:windowLightStatusBar">false</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorBackground</item>
|
||||
<item name="android:navigationBarColor">@android:color/transparent</item>
|
||||
<item name="android:windowLightNavigationBar">false</item>
|
||||
<item name="enableEdgeToEdge">true</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
||||
@@ -64,4 +64,9 @@
|
||||
<color name="safety_number_card_blue">#ff506ECD</color>
|
||||
|
||||
<color name="notification_background_ultramarine">#3B45FD</color>
|
||||
|
||||
<!-- Bottom-sheet dialog navigation bar color. Opaque below API 27 (keeps the legacy colored
|
||||
strip); overridden to transparent in values-v27 so Material's BottomSheetDialog lays the
|
||||
sheet out edge-to-edge and pads it for the navigation bar itself. -->
|
||||
<color name="bottom_sheet_navigation_bar_surface">@color/signal_colorSurface</color>
|
||||
</resources>
|
||||
|
||||
@@ -50,20 +50,14 @@
|
||||
|
||||
<style name="Theme.Signal.WallpaperCropper" parent="@style/TextSecure.DarkNoActionBar">
|
||||
<item name="colorPrimaryDark">@color/wallpaper_preview_background</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/wallpaper_preview_background</item>
|
||||
<item name="android:windowLightStatusBar" tools:ignore="NewApi">false</item>
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/wallpaper_preview_background</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">false</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.Signal.WallpaperCropper.Light" parent="@style/TextSecure.LightNoActionBar">
|
||||
<item name="colorPrimary">@color/wallpaper_preview_background</item>
|
||||
<item name="colorPrimaryDark">@color/wallpaper_preview_background</item>
|
||||
<item name="android:textColorSecondary">@color/white</item>
|
||||
<item name="android:windowTranslucentNavigation">true</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/wallpaper_preview_background</item>
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/wallpaper_preview_background</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">false</item>
|
||||
</style>
|
||||
|
||||
@@ -96,8 +90,6 @@
|
||||
<style name="TextSecure.LightIntroTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar">
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="27">default</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/signal_colorSurface</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorSurface</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="windowActionBar">false</item>
|
||||
@@ -113,8 +105,6 @@
|
||||
<style name="TextSecure.DarkIntroTheme" parent="@style/Theme.AppCompat">
|
||||
<item name="android:forceDarkAllowed" tools:targetApi="29">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="27">default</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/signal_colorSurface</item>
|
||||
<item name="android:navigationBarColor">@color/signal_colorSurface</item>
|
||||
<item name="android:windowLightStatusBar" tools:ignore="NewApi">false</item>
|
||||
<item name="android:windowActionBar">false</item>
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
@@ -446,7 +436,7 @@
|
||||
|
||||
<style name="Widget.Signal.FixedRoundedCorners.Messages" parent="Widget.Signal.FixedRoundedCorners">
|
||||
<item name="bottomSheetStyle">@style/Widget.Signal.FixedRoundedCorners.Messages.BottomSheet</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/signal_colorSurface</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/bottom_sheet_navigation_bar_surface</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Signal.FixedRoundedCorners.Messages.BottomSheet" parent="Widget.Material3.BottomSheet">
|
||||
@@ -457,7 +447,7 @@
|
||||
|
||||
<style name="Widget.Signal.FixedRoundedCorners.Stories">
|
||||
<item name="bottomSheetStyle">@style/Widget.Signal.FixedRoundedCorners.BottomSheet.Stories</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/signal_colorSurface</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/bottom_sheet_navigation_bar_surface</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Signal.FixedRoundedCorners.BottomSheet.Stories" parent="Widget.CoreUi.FixedRoundedCorners.BottomSheet">
|
||||
@@ -550,7 +540,7 @@
|
||||
|
||||
<item name="colorAccent">@color/core_ultramarine</item>
|
||||
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/signal_colorSurface1</item>
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/signal_bottom_sheet_navigation_bar</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">true</item>
|
||||
|
||||
<item name="android:colorForeground">@color/black</item>
|
||||
@@ -565,7 +555,7 @@
|
||||
|
||||
<item name="colorAccent">@color/core_ultramarine_light</item>
|
||||
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/signal_colorSurface1</item>
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/signal_bottom_sheet_navigation_bar</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">false</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/transparent</item>
|
||||
<item name="materialButtonStyle">@style/Widget.Signal.BottomSheet.MaterialButtonStyle</item>
|
||||
@@ -581,7 +571,7 @@
|
||||
|
||||
<item name="colorAccent">@color/signal_colorPrimary</item>
|
||||
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/signal_colorSurface</item>
|
||||
<item name="android:navigationBarColor" tools:ignore="NewApi">@color/bottom_sheet_navigation_bar_surface</item>
|
||||
<item name="android:windowLightNavigationBar" tools:ignore="NewApi">false</item>
|
||||
<item name="android:statusBarColor" tools:ignore="NewApi">@color/transparent</item>
|
||||
</style>
|
||||
|
||||
@@ -5,8 +5,15 @@
|
||||
|
||||
package org.signal.core.ui
|
||||
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.view.Window
|
||||
import android.view.WindowManager
|
||||
import androidx.core.view.WindowCompat
|
||||
import org.signal.core.ui.util.ThemeUtil
|
||||
|
||||
private val DARK_NAVIGATION_BAR_SCRIM = Color.argb(0x80, 0x1b, 0x1b, 0x1b)
|
||||
private val LIGHT_NAVIGATION_BAR_SCRIM = Color.argb(0xe6, 0xff, 0xff, 0xff)
|
||||
|
||||
/**
|
||||
* Initializes screenshot security on the window based on user preferences.
|
||||
@@ -18,3 +25,22 @@ fun Window.initializeScreenshotSecurity() {
|
||||
clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dialog-window analog of [androidx.activity.enableEdgeToEdge]: lays the window out edge-to-edge with
|
||||
* transparent (or scrimmed, pre-29) system bars, matching what targetSdk 36 enforces. Dialog windows are
|
||||
* not covered by the activity-level call in BaseActivity, so every non-floating dialog must opt in itself.
|
||||
*
|
||||
* Bar icon appearance (`windowLightStatusBar` / `windowLightNavigationBar`) is left to the window's theme,
|
||||
* which stays honored under edge-to-edge.
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
fun Window.enableEdgeToEdge() {
|
||||
WindowCompat.setDecorFitsSystemWindows(this, false)
|
||||
statusBarColor = Color.TRANSPARENT
|
||||
navigationBarColor = when {
|
||||
Build.VERSION.SDK_INT >= 29 -> Color.TRANSPARENT
|
||||
Build.VERSION.SDK_INT >= 27 && ThemeUtil.getThemedBoolean(context, android.R.attr.windowLightNavigationBar) -> LIGHT_NAVIGATION_BAR_SCRIM
|
||||
else -> DARK_NAVIGATION_BAR_SCRIM
|
||||
}
|
||||
}
|
||||
|
||||
+10
-2
@@ -10,7 +10,11 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.exclude
|
||||
import androidx.compose.foundation.layout.ime
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -45,8 +49,12 @@ abstract class ComposeBottomSheetDialogFragment : FixedRoundedCornerBottomSheetD
|
||||
}
|
||||
CompositionLocalProvider(LocalFragmentManager provides childFragmentManager) {
|
||||
SignalTheme(isDarkMode = isDark) {
|
||||
// No navigation bar padding here: BottomSheetBehavior already bottom-pads the sheet
|
||||
// for the navigation bar (paddingBottomSystemWindowInsets) once the window is
|
||||
// edge-to-edge, so padding again would double up. The keyboard inset excludes the
|
||||
// navigation bar for the same reason.
|
||||
Surface(
|
||||
modifier = Modifier.navigationBarsPadding(),
|
||||
modifier = Modifier.windowInsetsPadding(WindowInsets.ime.exclude(WindowInsets.navigationBars)),
|
||||
shape = RoundedCornerShape(cornerRadius.dp, cornerRadius.dp),
|
||||
color = SignalTheme.colors.colorSurface1,
|
||||
contentColor = MaterialTheme.colorScheme.onSurface
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.signal.core.ui.compose
|
||||
|
||||
import android.app.Dialog
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
@@ -20,6 +21,7 @@ import androidx.compose.ui.platform.ViewCompositionStrategy
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import org.signal.core.ui.R
|
||||
import org.signal.core.ui.compose.theme.SignalTheme
|
||||
import org.signal.core.ui.enableEdgeToEdge
|
||||
import org.signal.core.ui.initializeScreenshotSecurity
|
||||
import org.signal.core.ui.util.ThemeUtil
|
||||
|
||||
@@ -37,6 +39,12 @@ abstract class ComposeFullScreenDialogFragment : DialogFragment() {
|
||||
setStyle(STYLE_NO_FRAME, fullScreenDialogStyle)
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
return super.onCreateDialog(savedInstanceState).apply {
|
||||
window?.enableEdgeToEdge()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return ComposeView(requireContext()).apply {
|
||||
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Transparent on API 27+: Material's BottomSheetDialog only lays the sheet out edge-to-edge
|
||||
(and pads it for the navigation bar) when the window navigation bar color is non-opaque. -->
|
||||
<color name="signal_bottom_sheet_navigation_bar">@android:color/transparent</color>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- Bottom-sheet dialog navigation bar color. Opaque below API 27 (keeps the legacy colored
|
||||
strip); overridden to transparent in values-v27 so Material's BottomSheetDialog lays the
|
||||
sheet out edge-to-edge and pads it for the navigation bar itself. -->
|
||||
<color name="signal_bottom_sheet_navigation_bar">@color/signal_colorSurface1</color>
|
||||
|
||||
</resources>
|
||||
@@ -7,7 +7,7 @@
|
||||
<item name="bottomSheetStyle">@style/Widget.CoreUi.FixedRoundedCorners.BottomSheet</item>
|
||||
<item name="android:windowEnterAnimation">@anim/slide_from_bottom</item>
|
||||
<item name="android:windowExitAnimation">@anim/slide_to_bottom</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/signal_colorSurface1</item>
|
||||
<item name="android:navigationBarColor" tools:targetApi="lollipop">@color/signal_bottom_sheet_navigation_bar</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.CoreUi.FixedRoundedCorners.BottomSheet" parent="Widget.Material3.BottomSheet.Modal">
|
||||
|
||||
Reference in New Issue
Block a user