From 48a4a4c32e732a7dc4e225793b6520b7a9c985d6 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Wed, 10 Jun 2015 13:12:44 -0500 Subject: [PATCH] NavDrawer contents visible through status bar --- .../andlib/utility/AndroidUtilities.java | 4 + .../astrid/actfm/TagSettingsActivity.java | 2 +- .../astrid/activity/BeastModePreferences.java | 4 +- .../astrid/activity/TaskEditActivity.java | 2 +- .../InjectingPreferenceActivity.java | 7 + .../preferences/ActivityPreferences.java | 33 ++-- .../tasks/ui/NavigationDrawerFragment.java | 11 ++ .../org/tasks/ui/ScrimInsetsFrameLayout.java | 142 ++++++++++++++++++ .../res/layout/fragment_navigation_drawer.xml | 79 +++++----- src/main/res/values-v21/styles.xml | 1 + src/main/res/values/attrs.xml | 4 + 11 files changed, 239 insertions(+), 50 deletions(-) create mode 100644 src/main/java/org/tasks/ui/ScrimInsetsFrameLayout.java diff --git a/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java b/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java index d51247a84..72b5c67e6 100644 --- a/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java @@ -354,6 +354,10 @@ public class AndroidUtilities { return !atLeastJellybean(); } + public static boolean preLollipop() { + return !atLeastLollipop(); + } + public static boolean atLeastFroyo() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; } diff --git a/src/main/java/com/todoroo/astrid/actfm/TagSettingsActivity.java b/src/main/java/com/todoroo/astrid/actfm/TagSettingsActivity.java index efb06ef8c..f3d287f17 100644 --- a/src/main/java/com/todoroo/astrid/actfm/TagSettingsActivity.java +++ b/src/main/java/com/todoroo/astrid/actfm/TagSettingsActivity.java @@ -49,7 +49,7 @@ public class TagSettingsActivity extends InjectingAppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - preferences.applyTheme(); + preferences.applyThemeAndStatusBarColor(); setContentView(R.layout.tag_settings_activity); tagData = getIntent().getParcelableExtra(TagViewFragment.EXTRA_TAG_DATA); diff --git a/src/main/java/com/todoroo/astrid/activity/BeastModePreferences.java b/src/main/java/com/todoroo/astrid/activity/BeastModePreferences.java index 5cda2c77c..6ea2fdd09 100644 --- a/src/main/java/com/todoroo/astrid/activity/BeastModePreferences.java +++ b/src/main/java/com/todoroo/astrid/activity/BeastModePreferences.java @@ -21,6 +21,7 @@ import com.commonsware.cwac.tlv.TouchListView.DropListener; import org.tasks.R; import org.tasks.injection.InjectingListActivity; +import org.tasks.preferences.ActivityPreferences; import org.tasks.preferences.Preferences; import java.util.ArrayList; @@ -41,11 +42,12 @@ public class BeastModePreferences extends InjectingListActivity { private HashMap prefsToDescriptions; - @Inject Preferences preferences; + @Inject ActivityPreferences preferences; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + preferences.applyLightStatusBarColor(); setContentView(R.layout.beast_mode_pref_activity); setTitle(R.string.EPr_beastMode_desc); diff --git a/src/main/java/com/todoroo/astrid/activity/TaskEditActivity.java b/src/main/java/com/todoroo/astrid/activity/TaskEditActivity.java index 94e4ddb70..2886a8c6c 100644 --- a/src/main/java/com/todoroo/astrid/activity/TaskEditActivity.java +++ b/src/main/java/com/todoroo/astrid/activity/TaskEditActivity.java @@ -28,7 +28,7 @@ public class TaskEditActivity extends AstridActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - preferences.applyTheme(); + preferences.applyThemeAndStatusBarColor(); setContentView(R.layout.task_edit_wrapper_activity); diff --git a/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java b/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java index c01cf2ef3..06ece0cee 100644 --- a/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java +++ b/src/main/java/org/tasks/injection/InjectingPreferenceActivity.java @@ -8,6 +8,9 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import org.tasks.R; +import org.tasks.preferences.ActivityPreferences; + +import javax.inject.Inject; import dagger.ObjectGraph; @@ -17,6 +20,8 @@ public abstract class InjectingPreferenceActivity extends PreferenceActivity imp protected Toolbar toolbar; + @Inject ActivityPreferences activityPreferences; + @Override public void onCreate(Bundle savedInstanceState) { objectGraph = ((Injector) getApplication()).getObjectGraph().plus(new ActivityModule(this)); @@ -41,6 +46,8 @@ public abstract class InjectingPreferenceActivity extends PreferenceActivity imp finish(); } }); + + activityPreferences.applyLightStatusBarColor(); } @Override diff --git a/src/main/java/org/tasks/preferences/ActivityPreferences.java b/src/main/java/org/tasks/preferences/ActivityPreferences.java index 10ad3fc55..a252020eb 100644 --- a/src/main/java/org/tasks/preferences/ActivityPreferences.java +++ b/src/main/java/org/tasks/preferences/ActivityPreferences.java @@ -14,6 +14,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; +import static com.todoroo.andlib.utility.AndroidUtilities.preLollipop; @Singleton public class ActivityPreferences extends Preferences { @@ -33,20 +34,30 @@ public class ActivityPreferences extends Preferences { return isTabletSized(context); } + public void applyThemeAndStatusBarColor() { + applyTheme(); + applyStatusBarColor(); + } + public void applyTheme() { + applyTheme(isDarkTheme() ? R.style.Tasks_Dark : R.style.Tasks); + } + + public void applyStatusBarColor() { + applyStatusBarColor(isDarkTheme() ? android.R.color.black : R.color.primary_dark); + } + + public void applyLightStatusBarColor() { + applyStatusBarColor(R.color.primary_dark); + } + + private void applyStatusBarColor(int color) { + if (preLollipop()) { + return; + } Window window = activity.getWindow(); Resources resources = activity.getResources(); - if (isDarkTheme()) { - if (atLeastLollipop()) { - window.setStatusBarColor(resources.getColor(android.R.color.black)); - } - applyTheme(R.style.Tasks_Dark); - } else { - if (atLeastLollipop()) { - window.setStatusBarColor(resources.getColor(R.color.primary_dark)); - } - applyTheme(R.style.Tasks); - } + window.setStatusBarColor(resources.getColor(color)); } public void applyTranslucentDialogTheme() { diff --git a/src/main/java/org/tasks/ui/NavigationDrawerFragment.java b/src/main/java/org/tasks/ui/NavigationDrawerFragment.java index ee5ebde1e..760c94e42 100644 --- a/src/main/java/org/tasks/ui/NavigationDrawerFragment.java +++ b/src/main/java/org/tasks/ui/NavigationDrawerFragment.java @@ -7,6 +7,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.graphics.Bitmap; +import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.os.Bundle; import android.support.v4.view.GravityCompat; @@ -49,6 +50,8 @@ import org.tasks.preferences.Preferences; import javax.inject.Inject; +import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; + public class NavigationDrawerFragment extends InjectingFragment { private static final Logger log = LoggerFactory.getLogger(NavigationDrawerFragment.class); @@ -131,6 +134,14 @@ public class NavigationDrawerFragment extends InjectingFragment { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.fragment_navigation_drawer, container, false); + if (atLeastLollipop()) { + ((ScrimInsetsFrameLayout) layout.findViewById(R.id.scrim_layout)).setOnInsetsCallback(new ScrimInsetsFrameLayout.OnInsetsCallback() { + @Override + public void onInsetsChanged(Rect insets) { + mDrawerListView.setPadding(0, insets.top, 0, 0); + } + }); + } mDrawerListView = (ListView) layout.findViewById(android.R.id.list); mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override diff --git a/src/main/java/org/tasks/ui/ScrimInsetsFrameLayout.java b/src/main/java/org/tasks/ui/ScrimInsetsFrameLayout.java new file mode 100644 index 000000000..1d06c22cd --- /dev/null +++ b/src/main/java/org/tasks/ui/ScrimInsetsFrameLayout.java @@ -0,0 +1,142 @@ +/* + * Copyright 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.tasks.ui; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.support.v4.view.ViewCompat; +import android.util.AttributeSet; +import android.widget.FrameLayout; + +import org.tasks.R; + +/** + * A layout that draws something in the insets passed to {@link #fitSystemWindows(Rect)}, i.e. the area above UI chrome + * (status and navigation bars, overlay action bars). + */ +public class ScrimInsetsFrameLayout extends FrameLayout { + private Drawable mInsetForeground; + + private Rect mInsets; + private Rect mTempRect = new Rect(); + private OnInsetsCallback mOnInsetsCallback; + + public ScrimInsetsFrameLayout(Context context) { + super(context); + init(context, null, 0); + } + + public ScrimInsetsFrameLayout(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs, 0); + } + + public ScrimInsetsFrameLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs, defStyle); + } + + private void init(Context context, AttributeSet attrs, int defStyle) { + final TypedArray a = context.obtainStyledAttributes(attrs, + R.styleable.ScrimInsetsFrameLayout, defStyle, 0); + if (a == null) { + return; + } + mInsetForeground = a.getDrawable(R.styleable.ScrimInsetsFrameLayout_insetForeground); + a.recycle(); + + setWillNotDraw(true); + } + + @Override + protected boolean fitSystemWindows(Rect insets) { + mInsets = new Rect(insets); + setWillNotDraw(mInsetForeground == null); + ViewCompat.postInvalidateOnAnimation(this); + if (mOnInsetsCallback != null) { + mOnInsetsCallback.onInsetsChanged(insets); + } + return true; // consume insets + } + + @Override + public void draw(Canvas canvas) { + super.draw(canvas); + + int width = getWidth(); + int height = getHeight(); + if (mInsets != null && mInsetForeground != null) { + int sc = canvas.save(); + canvas.translate(getScrollX(), getScrollY()); + + // Top + mTempRect.set(0, 0, width, mInsets.top); + mInsetForeground.setBounds(mTempRect); + mInsetForeground.draw(canvas); + + // Bottom + mTempRect.set(0, height - mInsets.bottom, width, height); + mInsetForeground.setBounds(mTempRect); + mInsetForeground.draw(canvas); + + // Left + mTempRect.set(0, mInsets.top, mInsets.left, height - mInsets.bottom); + mInsetForeground.setBounds(mTempRect); + mInsetForeground.draw(canvas); + + // Right + mTempRect.set(width - mInsets.right, mInsets.top, width, height - mInsets.bottom); + mInsetForeground.setBounds(mTempRect); + mInsetForeground.draw(canvas); + + canvas.restoreToCount(sc); + } + } + + @Override + protected void onAttachedToWindow() { + super.onAttachedToWindow(); + if (mInsetForeground != null) { + mInsetForeground.setCallback(this); + } + } + + @Override + protected void onDetachedFromWindow() { + super.onDetachedFromWindow(); + if (mInsetForeground != null) { + mInsetForeground.setCallback(null); + } + } + + /** + * Allows the calling container to specify a callback for custom processing when insets change (i.e. when + * {@link #fitSystemWindows(Rect)} is called. This is useful for setting padding on UI elements based on + * UI chrome insets (e.g. a Google Map or a ListView). When using with ListView or GridView, remember to set + * clipToPadding to false. + */ + public void setOnInsetsCallback(OnInsetsCallback onInsetsCallback) { + mOnInsetsCallback = onInsetsCallback; + } + + public static interface OnInsetsCallback { + public void onInsetsChanged(Rect insets); + } +} \ No newline at end of file diff --git a/src/main/res/layout/fragment_navigation_drawer.xml b/src/main/res/layout/fragment_navigation_drawer.xml index ba54fd8d2..4866b3552 100644 --- a/src/main/res/layout/fragment_navigation_drawer.xml +++ b/src/main/res/layout/fragment_navigation_drawer.xml @@ -1,50 +1,57 @@ - - - + android:fitsSystemWindows="true" + android:background="?attr/drawer_background" + app:insetForeground="#4000"> - + android:layout_height="0dp" + android:layout_weight="1" + android:choiceMode="singleChoice" + android:divider="@android:color/transparent" + android:scrollbars="vertical" + android:clipToPadding="false" + tools:context=".NavigationDrawerFragment" /> -