NewContactActivity: properly implement edge-to-edge

This commit is contained in:
adbenitez
2025-11-25 22:30:20 +01:00
parent d41679f2c0
commit 18d9c00d13
6 changed files with 139 additions and 8 deletions
@@ -4,6 +4,7 @@ import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
@@ -11,12 +12,14 @@ import androidx.activity.EdgeToEdge;
import androidx.annotation.IdRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.view.WindowCompat;
import androidx.fragment.app.Fragment;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.Prefs;
import org.thoughtcrime.securesms.util.ViewUtil;
import java.lang.reflect.Field;
@@ -33,11 +36,28 @@ public abstract class BaseActionBarActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
onPreCreate();
EdgeToEdge.enable(this); // docs says to use: WindowCompat.enableEdgeToEdge(getWindow()); but it is not available
EdgeToEdge.enable(this); // TODO: docs says to use: WindowCompat.enableEdgeToEdge(getWindow()); but it requires dep androidx.core:core:1.17.0 which in turns requires to target SDK 36
super.onCreate(savedInstanceState);
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView()).setAppearanceLightStatusBars(false); // force white text in status bar
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// For activities without a custom toolbar, apply insets to status_bar_background view
View statusBarBackground = findViewById(R.id.status_bar_background);
if (statusBarBackground != null) {
ViewUtil.applyWindowInsetsAsHeight(statusBarBackground);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
// elevation is set via status_bar_background view
// otherwise there is a drop-shadow at the top
actionBar.setElevation(0);
}
}
}
@Override
protected void onResume() {
super.onResume();
@@ -42,9 +42,10 @@ public class NewContactActivity extends PassphraseRequiredActionBarActivity
actionBar.setTitle(R.string.menu_new_classic_contact);
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp);
actionBar.setElevation(0); // TODO: use custom toolbar instead
}
ViewUtil.applyWindowInsets(findViewById(R.id.content_container));
nameInput = ViewUtil.findById(this, R.id.name_text);
addrInput = ViewUtil.findById(this, R.id.email_text);
addrInput.setText(getIntent().getStringExtra(ADDR_EXTRA));
@@ -41,10 +41,12 @@ import androidx.annotation.IdRes;
import androidx.annotation.LayoutRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.interpolator.view.animation.FastOutSlowInInterpolator;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.util.views.Stub;
import chat.delta.util.ListenableFuture;
@@ -294,4 +296,91 @@ public class ViewUtil {
}
return selection;
}
/**
* Apply window insets to a view by adding padding to avoid drawing elements behind system bars.
* Convenience method that applies insets to all sides.
*
* @param view The view to apply insets to
*/
public static void applyWindowInsets(@NonNull View view) {
applyWindowInsets(view, true, true, true, true);
}
/**
* Apply window insets to a view by adding padding to avoid drawing elements behind system bars.
*
* This method stores the original padding values in view tags to ensure that
* padding doesn't accumulate on multiple inset applications.
*
* @param view The view to apply insets to
* @param left Whether to apply left inset
* @param top Whether to apply top inset
* @param right Whether to apply right inset
* @param bottom Whether to apply bottom inset
*/
public static void applyWindowInsets(@NonNull View view, boolean left, boolean top, boolean right, boolean bottom) {
// Store the original padding as a tag only if not already stored
// This prevents losing the true original padding on subsequent calls
if (view.getTag(R.id.tag_window_insets_padding_left) == null) {
view.setTag(R.id.tag_window_insets_padding_left, view.getPaddingLeft());
view.setTag(R.id.tag_window_insets_padding_top, view.getPaddingTop());
view.setTag(R.id.tag_window_insets_padding_right, view.getPaddingRight());
view.setTag(R.id.tag_window_insets_padding_bottom, view.getPaddingBottom());
}
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
// Retrieve the original padding values from tags with null checks
Integer leftTag = (Integer) v.getTag(R.id.tag_window_insets_padding_left);
Integer topTag = (Integer) v.getTag(R.id.tag_window_insets_padding_top);
Integer rightTag = (Integer) v.getTag(R.id.tag_window_insets_padding_right);
Integer bottomTag = (Integer) v.getTag(R.id.tag_window_insets_padding_bottom);
int basePaddingLeft = leftTag != null ? leftTag : 0;
int basePaddingTop = topTag != null ? topTag : 0;
int basePaddingRight = rightTag != null ? rightTag : 0;
int basePaddingBottom = bottomTag != null ? bottomTag : 0;
v.setPadding(
left ? basePaddingLeft + insets.left : basePaddingLeft,
top ? basePaddingTop + insets.top : basePaddingTop,
right ? basePaddingRight + insets.right : basePaddingRight,
bottom ? basePaddingBottom + insets.bottom : basePaddingBottom
);
return windowInsets;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
/**
* Apply the top status bar inset as the height of a view.
* This is useful for creating a colored status bar background view.
*
* @param view The view whose height should be set to the status bar inset
*/
public static void applyWindowInsetsAsHeight(@NonNull View view) {
ViewCompat.setOnApplyWindowInsetsListener(view, (v, windowInsets) -> {
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
android.view.ViewGroup.LayoutParams params = v.getLayoutParams();
if (params != null) {
params.height = insets.top;
v.setLayoutParams(params);
}
return windowInsets;
});
// Request the initial insets to be dispatched if the view is attached
if (view.isAttachedToWindow()) {
ViewCompat.requestApplyInsets(view);
}
}
}