Skip to content

Commit

Permalink
Customized navigation view theme with drawer options.
Browse files Browse the repository at this point in the history
  • Loading branch information
surinder-tsys committed May 16, 2023
1 parent ceb6cd6 commit 4e51cac
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 140 deletions.
18 changes: 18 additions & 0 deletions app/src/main/java/com/nmc/android/utils/DrawableThemeUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.nmc.android.utils

import android.graphics.drawable.Drawable
import androidx.annotation.ColorInt
import androidx.core.graphics.BlendModeColorFilterCompat
import androidx.core.graphics.BlendModeCompat
import androidx.core.graphics.drawable.DrawableCompat

object DrawableThemeUtils {
@JvmStatic
fun tintDrawable(drawable: Drawable, @ColorInt color: Int): Drawable {
val wrap: Drawable = DrawableCompat.wrap(drawable)
wrap.colorFilter = BlendModeColorFilterCompat.createBlendModeColorFilterCompat(
color, BlendModeCompat.SRC_ATOP
)
return wrap
}
}
170 changes: 53 additions & 117 deletions app/src/main/java/com/owncloud/android/ui/activity/DrawerActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,31 +35,18 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.text.TextUtils;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewGroup.MarginLayoutParams;
import android.webkit.URLUtil;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.bumptech.glide.GenericRequestBuilder;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.model.StreamEncoder;
import com.bumptech.glide.load.resource.file.FileToStreamDecoder;
import com.bumptech.glide.request.animation.GlideAnimation;
import com.bumptech.glide.request.target.SimpleTarget;
import com.google.android.material.button.MaterialButton;
Expand All @@ -73,6 +60,7 @@
import com.nextcloud.common.NextcloudClient;
import com.nextcloud.java.util.Optional;
import com.nextcloud.ui.ChooseAccountDialogFragment;
import com.nmc.android.utils.DrawableThemeUtils;
import com.owncloud.android.MainApp;
import com.owncloud.android.R;
import com.owncloud.android.authentication.PassCodeManager;
Expand Down Expand Up @@ -105,29 +93,26 @@
import com.owncloud.android.ui.fragment.SharedListFragment;
import com.owncloud.android.ui.preview.PreviewTextStringFragment;
import com.owncloud.android.ui.trashbin.TrashbinActivity;
import com.owncloud.android.utils.BitmapUtils;
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.DrawerMenuUtil;
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.StringUtils;
import com.owncloud.android.utils.svg.MenuSimpleTarget;
import com.owncloud.android.utils.svg.SVGorImage;
import com.owncloud.android.utils.svg.SvgOrImageBitmapTranscoder;
import com.owncloud.android.utils.svg.SvgOrImageDecoder;
import com.owncloud.android.utils.theme.CapabilityUtils;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.inject.Inject;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;
import androidx.core.view.GravityCompat;
Expand Down Expand Up @@ -165,11 +150,6 @@ public abstract class DrawerActivity extends ToolbarActivity
*/
private NavigationView mNavigationView;

/**
* Reference to the navigation view header.
*/
private View mNavigationViewHeader;

/**
* Flag to signal if the account chooser is active.
*/
Expand All @@ -195,6 +175,7 @@ public abstract class DrawerActivity extends ToolbarActivity
*/
private TextView mQuotaTextPercentage;
private TextView mQuotaTextLink;
private AppCompatTextView mQuotaTextUsage;

/**
* runnable that will be executed after the drawer has been closed.
Expand Down Expand Up @@ -230,10 +211,6 @@ protected void setupDrawer() {
mNavigationView = findViewById(R.id.nav_view);
if (mNavigationView != null) {

// Setting up drawer header
mNavigationViewHeader = mNavigationView.getHeaderView(0);
updateHeader();

setupDrawerMenu(mNavigationView);
getAndDisplayUserQuota();
setupQuotaElement();
Expand Down Expand Up @@ -292,86 +269,11 @@ private void setupQuotaElement() {
mQuotaView = (LinearLayout) findQuotaViewById(R.id.drawer_quota);
mQuotaProgressBar = (LinearProgressIndicator) findQuotaViewById(R.id.drawer_quota_ProgressBar);
mQuotaTextPercentage = (TextView) findQuotaViewById(R.id.drawer_quota_percentage);
mQuotaTextUsage = (AppCompatTextView) mNavigationView.findViewById(R.id.drawer_quota_usage);
mQuotaTextLink = (TextView) findQuotaViewById(R.id.drawer_quota_link);
viewThemeUtils.material.colorProgressBar(mQuotaProgressBar);
}

public void updateHeader() {
if (getAccount() != null &&
getCapabilities().getServerBackground() != null) {

OCCapability capability = getCapabilities();
String logo = capability.getServerLogo();
int primaryColor = themeColorUtils.unchangedPrimaryColor(getAccount(), this);

// set background to primary color
LinearLayout drawerHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_view);
drawerHeader.setBackgroundColor(primaryColor);

if (!TextUtils.isEmpty(logo) && URLUtil.isValidUrl(logo)) {
// background image
GenericRequestBuilder<Uri, InputStream, SVGorImage, Bitmap> requestBuilder = Glide.with(this)
.using(Glide.buildStreamModelLoader(Uri.class, this), InputStream.class)
.from(Uri.class)
.as(SVGorImage.class)
.transcode(new SvgOrImageBitmapTranscoder(128, 128), Bitmap.class)
.sourceEncoder(new StreamEncoder())
.cacheDecoder(new FileToStreamDecoder<>(new SvgOrImageDecoder()))
.decoder(new SvgOrImageDecoder());

// background image
SimpleTarget target = new SimpleTarget<Bitmap>() {
@Override
public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) {

Bitmap logo = resource;
int width = resource.getWidth();
int height = resource.getHeight();
int max = Math.max(width, height);
if (max > MAX_LOGO_SIZE_PX) {
logo = BitmapUtils.scaleBitmap(resource, MAX_LOGO_SIZE_PX, width, height, max);
}

Drawable[] drawables = {new ColorDrawable(primaryColor), new BitmapDrawable(logo)};
LayerDrawable layerDrawable = new LayerDrawable(drawables);

String name = capability.getServerName();
setDrawerHeaderLogo(layerDrawable, name);
}
};

requestBuilder
.diskCacheStrategy(DiskCacheStrategy.SOURCE)
.load(Uri.parse(logo))
.into(target);
}
}
}

private void setDrawerHeaderLogo(Drawable drawable, String name) {
ImageView imageHeader = mNavigationViewHeader.findViewById(R.id.drawer_header_logo);
imageHeader.setImageDrawable(drawable);
imageHeader.setScaleType(ImageView.ScaleType.FIT_START);
imageHeader.setAdjustViewBounds(true);

imageHeader.setMaxWidth(DisplayUtils.convertDpToPixel(100f, this));

MarginLayoutParams oldParam = (MarginLayoutParams) imageHeader.getLayoutParams();
MarginLayoutParams params = new MarginLayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
params.leftMargin = oldParam.leftMargin;
params.rightMargin = oldParam.rightMargin;

imageHeader.setLayoutParams(new LinearLayout.LayoutParams(params));

if (!TextUtils.isEmpty(name)) {
TextView serverName = mNavigationViewHeader.findViewById(R.id.drawer_header_server_name);
serverName.setText(name);
serverName.setTextColor(themeColorUtils.unchangedFontColor(this));
}

}

/**
* setup drawer content, basically setting the item selected listener.
*
Expand All @@ -397,7 +299,9 @@ private void filterDrawerMenu(final Menu menu, @NonNull final User user) {
OCCapability capability = getCapabilities();

DrawerMenuUtil.filterSearchMenuItems(menu, user, getResources());
DrawerMenuUtil.filterTrashbinMenuItem(menu, capability);
//trashbin icon is depending on capability due to this it doesn't appear in some of the devices
//so removing the check as we need this option always
//DrawerMenuUtil.filterTrashbinMenuItem(menu, capability);
DrawerMenuUtil.filterActivityMenuItem(menu, capability);
DrawerMenuUtil.filterGroupfoldersMenuItem(menu, capability);

Expand Down Expand Up @@ -684,19 +588,18 @@ private void showQuota(boolean showQuota) {
* @param quotaValue {@link GetUserInfoRemoteOperation#SPACE_UNLIMITED} or other to determinate state
*/
private void setQuotaInformation(long usedSpace, long totalSpace, int relative, long quotaValue) {
if (GetUserInfoRemoteOperation.SPACE_UNLIMITED == quotaValue) {
mQuotaTextPercentage.setText(String.format(
getString(R.string.drawer_quota_unlimited),
DisplayUtils.bytesToHumanReadable(usedSpace)));
} else {
mQuotaTextPercentage.setText(String.format(
getString(R.string.drawer_quota),
DisplayUtils.bytesToHumanReadable(usedSpace),
DisplayUtils.bytesToHumanReadable(totalSpace)));
}
String usageText = String.format(
getString(R.string.drawer_quota_usage),
DisplayUtils.bytesToHumanReadable(usedSpace),
DisplayUtils.bytesToHumanReadable(totalSpace));

mQuotaTextUsage.setText(StringUtils.makeTextBold(usageText, DisplayUtils.bytesToHumanReadable(usedSpace)));

mQuotaProgressBar.setProgress(relative);

mQuotaTextPercentage.setText(String.format(
getString(R.string.drawer_quota_percentage), relative));

if (relative < RELATIVE_THRESHOLD_WARNING) {
viewThemeUtils.material.colorProgressBar(mQuotaProgressBar);
} else {
Expand Down Expand Up @@ -784,10 +687,43 @@ public void onLoadFailed(Exception e, Drawable errorDrawable) {
* @param menuItemId the menu item to be highlighted
*/
protected void setDrawerMenuItemChecked(int menuItemId) {
//NMC customisation
//if item is logout then do not show it as selected
if (menuItemId == R.id.nav_logout) {
//if previous checked item is not NONE then make it selected again
//to show it as selected bg color
if (mCheckedMenuItem != Menu.NONE) {
setDrawerMenuItemChecked(mCheckedMenuItem);
}
return;
}

if (mNavigationView != null && mNavigationView.getMenu().findItem(menuItemId) != null) {
viewThemeUtils.platform.colorNavigationView(mNavigationView);
mCheckedMenuItem = menuItemId;
mNavigationView.getMenu().findItem(menuItemId).setChecked(true);

//for NMC customization
MenuItem currentItem = mNavigationView.getMenu().findItem(menuItemId);
int drawerDefaultTxtColor = getResources().getColor(R.color.nav_txt_unselected_color);
int drawerActiveTxtColor = getResources().getColor(R.color.nav_txt_selected_color);

int drawerDefaultIconColor = getResources().getColor(R.color.nav_icon_unselected_color);
int drawerActiveIconColor = getResources().getColor(R.color.nav_icon_selected_color);

currentItem.setChecked(true);

// For each menu item, change the color of the selected item, and of the other items
for (int i = 0; i < mNavigationView.getMenu().size(); i++) {
MenuItem menuItem = mNavigationView.getMenu().getItem(i);
if (menuItem.getIcon() != null) {
if (menuItem == currentItem) {
DrawableThemeUtils.tintDrawable(currentItem.getIcon(), drawerActiveIconColor);
currentItem.setTitle(StringUtils.getColorSpan(currentItem.getTitle().toString(), drawerActiveTxtColor));
} else {
DrawableThemeUtils.tintDrawable(menuItem.getIcon(), drawerDefaultIconColor);
menuItem.setTitle(StringUtils.getColorSpan(menuItem.getTitle().toString(), drawerDefaultTxtColor));
}
}
}
} else {
Log_OC.w(TAG, "setDrawerMenuItemChecked has been called with invalid menu-item-ID");
}
Expand Down Expand Up @@ -1018,7 +954,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
* @return The view if found or <code>null</code> otherwise.
*/
private View findQuotaViewById(int id) {
View v = ((NavigationView) findViewById(R.id.nav_view)).getHeaderView(0).findViewById(id);
View v = ((NavigationView) findViewById(R.id.nav_view)).findViewById(id);

if (v != null) {
return v;
Expand Down
30 changes: 30 additions & 0 deletions app/src/main/java/com/owncloud/android/utils/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@
package com.owncloud.android.utils;


import android.text.Spannable;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;

import java.util.Locale;
import android.graphics.Typeface;
import android.text.style.StyleSpan;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand Down Expand Up @@ -69,6 +75,15 @@ String searchAndColor(@Nullable String text, @Nullable String searchText,
}
}

public static Spannable getColorSpan(@NonNull String title, @ColorInt int color) {
Spannable text = new SpannableString(title);
text.setSpan(new ForegroundColorSpan(color),
0,
text.length(),
Spannable.SPAN_INCLUSIVE_INCLUSIVE);
return text;
}

public static
@NonNull
String removePrefix(@NonNull String s, @NonNull String prefix) {
Expand All @@ -77,4 +92,19 @@ String removePrefix(@NonNull String s, @NonNull String prefix) {
}
return s;
}

/**
* make the passed text bold
*
* @param fullText actual text
* @param textToBold to be bold
* @return
*/
public static Spannable makeTextBold(String fullText, String textToBold) {
Spannable spannable = new SpannableString(fullText);
int indexStart = fullText.indexOf(textToBold);
int indexEnd = indexStart + textToBold.length();
spannable.setSpan(new StyleSpan(Typeface.BOLD), indexStart, indexEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannable;
}
}
31 changes: 31 additions & 0 deletions app/src/main/res/drawable/ic_magentacloud_product_logo.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="40dp"
android:height="40dp"
android:viewportWidth="40"
android:viewportHeight="40">
<group>
<clip-path
android:pathData="M0,0h40v40h-40z"/>
<path
android:pathData="M2.133,0H37.867A2.133,2.133 0,0 1,40 2.133V37.867A2.133,2.133 0,0 1,37.867 40H2.133A2.133,2.133 0,0 1,0 37.867V2.133A2.133,2.133 0,0 1,2.133 0Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="20"
android:startY="0"
android:endX="20"
android:endY="40"
android:type="linear">
<item android:offset="0" android:color="#FFFE319A"/>
<item android:offset="1" android:color="#FFE20074"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M17.63,30.545a9.886,9.886 0,0 1,-6.811 -2.706,5.4 5.4,0 0,1 -1.188,0.132A5.364,5.364 0,0 1,8.467 17.367a5.328,5.328 0,0 1,6.83 -4.8A8.963,8.963 0,0 1,18.367 10.021a8.877,8.877 0,0 1,1.92 -0.706,8.934 8.934,0 0,1 9.855,4.259 8.843,8.843 0,0 1,1.048 2.95,5.688 5.688,0 0,1 1.8,0.72 5.733,5.733 0,0 1,-3 10.623,5.836 5.836,0 0,1 -0.608,-0.032 5.329,5.329 0,0 1,-6.3 1.224L23.082,22.35h4.423L20.786,15.461 14.015,22.35L18.477,22.35v8.16C18.196,30.533 17.911,30.545 17.63,30.545Z"
android:fillColor="#fff"/>
<path
android:pathData="M27.519,23.889L23.096,23.889L23.096,22.349h2.918l1.505,1.54ZM18.476,23.889L13.976,23.889L15.499,22.349L18.476,22.349L18.476,23.889Z"
android:fillColor="#f9cce3"/>
</group>
</vector>
4 changes: 4 additions & 0 deletions app/src/main/res/drawable/menu_background_color_state.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@color/nav_selected_bg_color" android:state_checked="true" />
</selector>
Loading

0 comments on commit 4e51cac

Please sign in to comment.