Update ProGuard once again. Add Toolbar subtitle unread badge. Remove debug toast. Add user attention ripple. Add drawer icon unread badge.

This commit is contained in:
kubasz 2019-09-09 19:47:55 +02:00
parent 9e2e4f6057
commit 345cf00311
20 changed files with 318 additions and 30 deletions

View File

@ -15,7 +15,7 @@ android {
}
buildTypes {
release {
minifyEnabled false
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}

View File

@ -19,3 +19,11 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keep class .R
-keep class **.R$* {
<fields>;
}
-keep class android.support.v7.** { *; }
-keep interface android.support.v7.** { *; }

View File

@ -217,9 +217,18 @@ class MainActivity : AppCompatActivity() {
navView.bottomBar.fabExtendedText = "Compose"
navView.bottomBar.fabExtended = false
rippleButton.setOnClickListener {
navView.gainAttentionOnBottomBar()
}
navView.toolbar.subtitleFormat = R.string.toolbar_subtitle
navView.toolbar.subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
navView.drawer.apply {
miniDrawerVisiblePortrait = true
miniDrawerVisibleLandscape = null
addUnreadCounterType(type = 10, drawerItem = 1)
addUnreadCounterType(type = 20, drawerItem = 2)
addUnreadCounterType(type = 30, drawerItem = 60)
@ -313,6 +322,7 @@ class MainActivity : AppCompatActivity() {
)
drawerItemSelectedListener = { id, position, drawerItem ->
navView.gainAttentionOnBottomBar()
if (id == 1 || id == 2) {
getItemById(id) {
if (it is DrawerPrimaryItem) {
@ -328,6 +338,8 @@ class MainActivity : AppCompatActivity() {
// drawer item ID)
// See with "Settings" when it.badge AND UnreadCounter is present.
//
// and it of course does not update the badge
//
// just do not do this.
it.badge = StringHolder("${it.tag as Int * 10}")
}

View File

@ -29,6 +29,11 @@
android:layout_width="wrap_content"
android:layout_height="48dp"
android:text="Switch theme" />
<Button
android:id="@+id/rippleButton"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:text="Ripple bottombar" />
<TextView
android:layout_width="match_parent"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="toolbar_subtitle_with_unread">
<item quantity="one">%1$s - %2$d nieprzeczytane</item>
<item quantity="few">%1$s - %2$d nieprzeczytane</item>
<item quantity="many">%1$s - %2$d nieprzeczytanych</item>
</plurals>
</resources>

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<plurals name="toolbar_subtitle_with_unread">
<item quantity="other">%1$s - %2$d unread</item>
</plurals>
</resources>

View File

@ -50,4 +50,6 @@ dependencies {
implementation "com.mikepenz:itemanimators:1.1.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
implementation "pl.droidsonroids.gif:android-gif-drawable:${versions.gifdrawable}"
implementation 'com.balysv:material-ripple:1.0.2'
}

View File

@ -0,0 +1,2 @@
-keep class androidx.drawerlayout.widget.DrawerLayout { *; }
-keep class androidx.customview.widget.ViewDragHelper { *; }

View File

@ -20,4 +20,5 @@
# hide the original source file name.
#-renamesourcefileattribute SourceFile
-keepclassmembers class androidx.drawerlayout.widget.DrawerLayout { *; }
-keep class androidx.drawerlayout.widget.DrawerLayout { *; }
-keep class androidx.customview.widget.ViewDragHelper { *; }

View File

@ -0,0 +1,109 @@
package pl.szczodrzynski.navlib;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import androidx.core.content.ContextCompat;
public class BadgeDrawable extends Drawable {
private Paint mBadgePaint;
private Paint mBadgePaint1;
private Paint mTextPaint;
private Rect mTxtRect = new Rect();
private String mCount = "";
private boolean mWillDraw = false;
public BadgeDrawable(Context context) {
float mTextSize = context.getResources().getDimension(R.dimen.badge_text_size);
mBadgePaint = new Paint();
mBadgePaint.setColor(0xffff3d00);
mBadgePaint.setAntiAlias(true);
mBadgePaint.setStyle(Paint.Style.FILL);
/*mBadgePaint1 = new Paint();
mBadgePaint1.setColor(ContextCompat.getColor(context.getApplicationContext(), R.color.grey_ivory5));
mBadgePaint1.setAntiAlias(true);
mBadgePaint1.setStyle(Paint.Style.FILL);*/
mTextPaint = new Paint();
mTextPaint.setColor(Color.WHITE);
mTextPaint.setTypeface(Typeface.DEFAULT);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setAntiAlias(true);
mTextPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
public void draw(Canvas canvas) {
if (!mWillDraw) {
return;
}
Rect bounds = getBounds();
float width = bounds.right - bounds.left;
float height = bounds.bottom - bounds.top;
// Position the badge in the top-right quadrant of the icon.
/*Using Math.max rather than Math.min */
float radius = ((Math.max(width, height) / 2)) / 2;
float centerX = (width - radius - 1) +5;
float centerY = radius -5;
if(mCount.length() <= 2){
// Draw badge circle.
//canvas.drawCircle(centerX, centerY, (int)(radius+7.5), mBadgePaint1);
canvas.drawCircle(centerX, centerY, (int)(radius+5.5), mBadgePaint);
}
else{
//canvas.drawCircle(centerX, centerY, (int)(radius+8.5), mBadgePaint1);
canvas.drawCircle(centerX, centerY, (int)(radius+6.5), mBadgePaint);
// canvas.drawRoundRect(radius, radius, radius, radius, 10, 10, mBadgePaint);
}
// Draw badge count text inside the circle.
mTextPaint.getTextBounds(mCount, 0, mCount.length(), mTxtRect);
float textHeight = mTxtRect.bottom - mTxtRect.top;
float textY = centerY + (textHeight / 2f);
if(mCount.length() > 2)
canvas.drawText("99+", centerX, textY, mTextPaint);
else
canvas.drawText(mCount, centerX, textY, mTextPaint);
}
/*
Sets the count (i.e notifications) to display.
*/
public void setCount(String count) {
mCount = count;
// Only draw a badge if there are notifications.
mWillDraw = !count.equalsIgnoreCase("0");
invalidateSelf();
}
@Override
public void setAlpha(int alpha) {
// do nothing
}
@Override
public void setColorFilter(ColorFilter cf) {
// do nothing
}
@Override
public int getOpacity() {
return PixelFormat.UNKNOWN;
}
}

View File

@ -1,11 +1,13 @@
package pl.szczodrzynski.navlib
import android.content.Context
import android.graphics.drawable.LayerDrawable
import android.util.AttributeSet
import android.view.Gravity
import android.view.MenuItem
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import com.google.android.material.bottomappbar.BottomAppBar
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
@ -112,10 +114,16 @@ class NavBottomBar : BottomAppBar {
elevation = 0f
navigationIcon = IconicsDrawable(context)
.icon(CommunityMaterial.Icon2.cmd_menu)
.sizeDp(20)
.colorInt(getColorFromAttr(context, R.attr.colorOnPrimary))
val icon = ContextCompat.getDrawable(context, R.drawable.ic_menu_badge) as LayerDrawable?
icon?.apply {
mutate()
setDrawableByLayerId(R.id.ic_menu, IconicsDrawable(context)
.icon(CommunityMaterial.Icon2.cmd_menu)
.sizeDp(20)
.colorInt(getColorFromAttr(context, R.attr.colorOnPrimary)))
setDrawableByLayerId(R.id.ic_badge, BadgeDrawable(context))
}
navigationIcon = icon
menu.add(0, -1, 0, "Menu")
.setIcon(

View File

@ -31,6 +31,9 @@ class NavToolbar : MaterialToolbar {
}
var subtitleFormat: Int? = null
var subtitleFormatWithUnread: Int? = null
var profileImageClickListener: (() -> Unit)? = null
var profileImage

View File

@ -3,6 +3,7 @@ package pl.szczodrzynski.navlib
import android.content.Context
import android.content.res.Configuration
import android.content.res.Configuration.ORIENTATION_PORTRAIT
import android.graphics.Point
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
@ -15,9 +16,12 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
import com.google.android.material.floatingactionbutton.FloatingActionButton
import kotlinx.android.synthetic.main.nav_view.view.*
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
import pl.szczodrzynski.navlib.drawer.NavDrawer
import android.graphics.drawable.RippleDrawable
import android.os.Build
import androidx.core.view.children
import com.mikepenz.materialize.util.UIUtils
class NavView : FrameLayout {
@ -39,6 +43,9 @@ class NavView : FrameLayout {
lateinit var toolbar: NavToolbar
lateinit var bottomBar: NavBottomBar
lateinit var bottomSheet: NavBottomSheet
val coordinator by lazy {
findViewById<CoordinatorLayout>(R.id.nv_coordinator)
}
var navigationLoader: NavigationLoader? = null
@ -95,9 +102,20 @@ class NavView : FrameLayout {
bottomBar.fabView = floatingActionButton
bottomBar.fabExtendedView = extendedFloatingActionButton
ripple.isEnabled = false
ripple.children.forEach { it.isEnabled = false }
//bottomSheetBehavior.peekHeight = displayHeight
}
fun gainAttentionOnBottomBar() {
var x = ripple.width.toFloat()
var y = ripple.height.toFloat()
x -= UIUtils.convertDpToPixel(56f, context) / 2
y -= UIUtils.convertDpToPixel(56f, context) / 2
ripple.performRipple(Point(x.toInt(), y.toInt()))
}
fun configSystemBarsUtil(systemBarsUtil: SystemBarsUtil) {
this.systemBarsUtil = systemBarsUtil.apply {
this.statusBarBgView = statusBarBackground

View File

@ -297,7 +297,6 @@ class SystemBarsUtil(private val activity: Activity) {
if (insetsListener != null) {
if (SDK_INT >= LOLLIPOP) {
ViewCompat.setOnApplyWindowInsetsListener(insetsListener!!) { _, insets ->
Toast.makeText(activity, "Insets applied ", Toast.LENGTH_SHORT).show()
Log.d("NavLib", "Got insets left = ${insets.systemWindowInsetLeft}, top = ${insets.systemWindowInsetTop}, right = ${insets.systemWindowInsetRight}, bottom = ${insets.systemWindowInsetBottom}")
if (insetsApplied)
return@setOnApplyWindowInsetsListener insets.consumeSystemWindowInsets()

View File

@ -7,10 +7,12 @@ import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.LayerDrawable
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.customview.widget.ViewDragHelper
import androidx.drawerlayout.widget.DrawerLayout
@ -84,11 +86,11 @@ class NavDrawer(
.withTranslucentStatusBar(false)
.withTranslucentNavigationBar(true)
.withTranslucentNavigationBarProgrammatically(false)
.withToolbar(bottomBar)
//.withToolbar(bottomBar)
.withDisplayBelowStatusBar(false)
.withActionBarDrawerToggleAnimated(true)
//.withActionBarDrawerToggleAnimated(true)
.withShowDrawerOnFirstLaunch(true)
.withShowDrawerUntilDraggedOpened(true)
//.withShowDrawerUntilDraggedOpened(true)
.withGenerateMiniDrawer(true /* if it is not showing on screen, clicking items throws an exception */)
.withOnDrawerListener(object : Drawer.OnDrawerListener {
override fun onDrawerSlide(drawerView: View, slideOffset: Float) {}
@ -278,24 +280,51 @@ class NavDrawer(
| | | | | |\ V / (_| | || __/ | | | | | | __/ |_| | | | (_) | (_| \__ \
|_| |_| |_| \_/ \__,_|\__\___| |_| |_| |_|\___|\__|_| |_|\___/ \__,_|__*/
private fun drawerSetDragMargin(size: Float) {
val mDrawerLayout = drawer?.drawerLayout
val mDragger = mDrawerLayout?.javaClass?.getDeclaredField(
"mLeftDragger"
)//mRightDragger for right obviously
mDragger?.isAccessible = true
val draggerObj = mDragger?.get(mDrawerLayout) as ViewDragHelper?
try {
val mDrawerLayout = drawer?.drawerLayout
val mDragger = mDrawerLayout?.javaClass?.getDeclaredField(
"mLeftDragger"
)//mRightDragger for right obviously
mDragger?.isAccessible = true
val draggerObj = mDragger?.get(mDrawerLayout) as ViewDragHelper?
val mEdgeSize = draggerObj?.javaClass?.getDeclaredField(
"mEdgeSize"
)
mEdgeSize?.isAccessible = true
val mEdgeSize = draggerObj?.javaClass?.getDeclaredField(
"mEdgeSize"
)
mEdgeSize?.isAccessible = true
mEdgeSize?.setInt(
draggerObj,
size.toInt()
) //optimal value as for me, you may set any constant in dp
mEdgeSize?.setInt(
draggerObj,
size.toInt()
) //optimal value as for me, you may set any constant in dp
}
catch (e: Exception) {
e.printStackTrace()
Toast.makeText(context, "Oops, proguard works", Toast.LENGTH_SHORT).show()
}
}
var miniDrawerVisiblePortrait: Boolean? = null
set(value) {
field = value
val configuration = context.resources.configuration
decideDrawerMode(
configuration.orientation,
configuration.screenWidthDp,
configuration.screenHeightDp
)
}
var miniDrawerVisibleLandscape: Boolean? = null
set(value) {
field = value
val configuration = context.resources.configuration
decideDrawerMode(
configuration.orientation,
configuration.screenWidthDp,
configuration.screenHeightDp
)
}
internal fun decideDrawerMode(orientation: Int, widthDp: Int, heightDp: Int) {
Log.d("NavLib", "Deciding drawer mode:")
if (orientation == Configuration.ORIENTATION_PORTRAIT) {
@ -314,7 +343,7 @@ class NavDrawer(
}
Log.d("NavLib", "- mini drawer land disabled")
if (widthDp >= 480) {
if ((widthDp >= 480 && miniDrawerVisiblePortrait != false) || miniDrawerVisiblePortrait == true) {
if (miniDrawerView == null)
miniDrawerView = miniDrawer?.build(context)
if (miniDrawerContainerPortrait.indexOfChild(miniDrawerView) == -1)
@ -339,7 +368,7 @@ class NavDrawer(
}
Log.d("NavLib", "- mini drawer port disabled")
if (widthDp in 480 until 9000) {
if ((widthDp in 480 until 9000 && miniDrawerVisibleLandscape != false) || miniDrawerVisibleLandscape == true) {
if (miniDrawerView == null)
miniDrawerView = miniDrawer?.build(context)
if (miniDrawerContainerLandscape.indexOfChild(miniDrawerView) == -1)
@ -515,6 +544,7 @@ class NavDrawer(
profileList = profiles as MutableList<IDrawerProfile>
updateProfileList()
}
private var currentProfileObj: IDrawerProfile? = null
val profileListEmpty: Boolean
get() = profileList.isEmpty()
var currentProfile: Int
@ -522,7 +552,8 @@ class NavDrawer(
set(value) {
Log.d("NavDebug", "currentProfile = $value")
accountHeader?.setActiveProfile(value.toLong(), false)
setToolbarProfileImage(profileList.singleOrNull { it.id == value })
currentProfileObj = profileList.singleOrNull { it.id == value }
setToolbarProfileImage(currentProfileObj)
updateBadges()
}
fun appendProfile(profile: IDrawerProfile) {
@ -595,10 +626,14 @@ class NavDrawer(
private val unreadCounterTypeMap = mutableMapOf<Int, Int>()
fun updateBadges() {
currentProfileObj = profileList.singleOrNull { it.id == currentProfile }
Log.d("NavDebug", "updateBadges()")
unreadCounterList.map {
it.drawerItemId = unreadCounterTypeMap[it.type]
}
var totalCount = 0
unreadCounterList.forEach {
if (it.drawerItemId == null)
return@forEach
@ -616,8 +651,36 @@ class NavDrawer(
else -> StringHolder(it.count.toString())
}
)
totalCount += it.count
}
updateMiniDrawer()
if (bottomBar.navigationIcon is LayerDrawable) {
(bottomBar.navigationIcon as LayerDrawable?)?.apply {
findDrawableByLayerId(R.id.ic_badge)
.takeIf { it is BadgeDrawable }
?.also { badge ->
(badge as BadgeDrawable).setCount(totalCount.toString())
mutate()
setDrawableByLayerId(R.id.ic_badge, badge)
}
}
}
if (totalCount == 0) {
toolbar.subtitle = resources.getString(
toolbar.subtitleFormat ?: return,
currentProfileObj?.name ?: ""
)
}
else {
toolbar.subtitle = resources.getQuantityString(
toolbar.subtitleFormatWithUnread ?: toolbar.subtitleFormat ?: return,
totalCount,
currentProfileObj?.name ?: "",
totalCount
)
}
}
fun setUnreadCounterList(unreadCounterList: MutableList<out IUnreadCounter>) {

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/ic_menu"
android:drawable="@drawable/placeholder"
android:gravity="center" />
<item
android:id="@+id/ic_badge"
android:drawable="@drawable/placeholder" />
</layer-list>

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
</shape>

View File

@ -40,9 +40,10 @@
android:id="@+id/nv_miniDrawerContainerLandscape"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:background="#2196f3" /><!--tools:layout_width="72dp"-->
android:background="@color/colorSurface_4dp"/><!--tools:layout_width="72dp"-->
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:id="@+id/nv_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -53,6 +54,7 @@
android:background="?actionBarBackground"
android:elevation="4dp"
app:title="@string/app_name"
app:subtitle="Phil Swift - 10 unread"
tools:targetApi="lollipop">
<com.mikepenz.materialdrawer.view.BezelImageView
@ -89,7 +91,7 @@
android:id="@+id/nv_miniDrawerContainerPortrait"
android:layout_width="wrap_content"
android:layout_height="match_parent"
tools:background="#ffb300" /><!--tools:layout_width="72dp"-->
android:background="@color/colorSurface_4dp" /><!--tools:layout_width="72dp"-->
<View
android:id="@+id/nv_miniDrawerElevation"
@ -105,10 +107,34 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:gravity="start"
android:visibility="visible"
app:fabAlignmentMode="center"
app:fabAnimationMode="scale" />
<com.balysv.materialripple.MaterialRippleLayout
android:id="@+id/ripple"
android:layout_width="100dp"
android:layout_height="?actionBarSize"
android:layout_gravity="bottom|end"
android:enabled="false"
android:focusableInTouchMode="false"
android:focusable="false"
app:mrl_rippleFadeDuration="200"
app:mrl_rippleDuration="350"
app:mrl_rippleColor="?colorOnBackground"
app:mrl_rippleAlpha="0.3">
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:enabled="false"
android:focusableInTouchMode="false"
android:focusable="false"
android:visibility="invisible"/>
</com.balysv.materialripple.MaterialRippleLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/nv_extendedFloatingActionButton"
android:layout_width="wrap_content"

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="badge_text_size">10sp</dimen>
</resources>

View File

@ -1,3 +1,4 @@
<resources>
<string name="app_name">NavLib</string>
<string name="toolbar_subtitle">%1$s</string>
</resources>