Skip to content

Commit a40704a

Browse files
feat(theming): Theme NavigationView
Signed-off-by: Stefan Niedermann <info@niedermann.it>
1 parent 05a4fad commit a40704a

8 files changed

Lines changed: 108 additions & 22 deletions

File tree

app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import androidx.annotation.ColorInt;
77
import androidx.annotation.NonNull;
88
import androidx.core.app.ActivityCompat;
9+
import androidx.core.content.ContextCompat;
910
import androidx.lifecycle.LiveData;
1011
import androidx.preference.PreferenceManager;
1112

@@ -57,14 +58,14 @@ public static BrandingUtil of(@ColorInt int color, @NonNull Context context) {
5758
public static LiveData<Integer> readBrandMainColorLiveData(@NonNull Context context) {
5859
final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
5960
Log.v(TAG, "--- Read: shared_preference_theme_main");
60-
return new SharedPreferenceIntLiveData(sharedPreferences, pref_key_branding_main, context.getApplicationContext().getResources().getColor(R.color.defaultBrand));
61+
return new SharedPreferenceIntLiveData(sharedPreferences, pref_key_branding_main, ContextCompat.getColor(context, R.color.defaultBrand));
6162
}
6263

6364
@ColorInt
6465
public static int readBrandMainColor(@NonNull Context context) {
6566
final var sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
6667
Log.v(TAG, "--- Read: shared_preference_theme_main");
67-
return sharedPreferences.getInt(pref_key_branding_main, context.getApplicationContext().getResources().getColor(R.color.defaultBrand));
68+
return sharedPreferences.getInt(pref_key_branding_main, ContextCompat.getColor(context, R.color.defaultBrand));
6869
}
6970

7071
public static void saveBrandColor(@NonNull Context context, @ColorInt int color) {

app/src/main/java/it/niedermann/owncloud/notes/branding/NotesViewThemeUtils.java

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package it.niedermann.owncloud.notes.branding;
22

3+
import static com.nextcloud.android.common.ui.util.ColorStateListUtilsKt.buildColorStateList;
34
import static it.niedermann.owncloud.notes.NotesApplication.isDarkThemeActive;
45

56
import android.content.Context;
67
import android.graphics.Color;
78
import android.graphics.PorterDuff;
89
import android.graphics.drawable.LayerDrawable;
910
import android.util.Log;
11+
import android.view.View;
12+
import android.widget.ImageView;
13+
import android.widget.TextView;
1014

1115
import androidx.annotation.ColorInt;
1216
import androidx.annotation.IdRes;
@@ -16,27 +20,79 @@
1620
import androidx.core.graphics.drawable.DrawableCompat;
1721

1822
import com.google.android.material.appbar.AppBarLayout;
23+
import com.google.android.material.appbar.MaterialToolbar;
24+
import com.google.android.material.navigation.NavigationView;
1925
import com.nextcloud.android.common.ui.theme.MaterialSchemes;
2026
import com.nextcloud.android.common.ui.theme.ViewThemeUtilsBase;
27+
import com.nextcloud.android.common.ui.theme.utils.MaterialViewThemeUtils;
2128

2229
import it.niedermann.android.util.ColorUtil;
2330
import it.niedermann.owncloud.notes.R;
31+
import it.niedermann.owncloud.notes.main.navigation.NavigationItem;
2432
import it.niedermann.owncloud.notes.shared.util.NotesColorUtil;
33+
import kotlin.Pair;
2534
import scheme.Scheme;
2635

2736
public class NotesViewThemeUtils extends ViewThemeUtilsBase {
2837

2938
private static final String TAG = NotesViewThemeUtils.class.getSimpleName();
39+
private final MaterialSchemes schemes;
3040

3141
public NotesViewThemeUtils(@NonNull MaterialSchemes schemes) {
3242
super(schemes);
43+
this.schemes = schemes;
3344
}
3445

3546
@ColorInt
3647
public int getOnPrimaryContainer(@NonNull Context context) {
3748
return withScheme(context, Scheme::getOnPrimaryContainer);
3849
}
3950

51+
/**
52+
* The Notes app uses custom navigation view items because they have several features which are
53+
* not covered by {@link NavigationItem}.
54+
*/
55+
public void colorNavigationViewItem(@NonNull View view) {
56+
withScheme(view, scheme -> {
57+
view.setBackgroundTintList(buildColorStateList(
58+
new Pair<>(android.R.attr.state_selected, scheme.getSecondaryContainer()),
59+
new Pair<>(-android.R.attr.state_selected, Color.TRANSPARENT)
60+
));
61+
return view;
62+
});
63+
}
64+
65+
/**
66+
* The Notes app uses custom navigation view items because they have several features which are
67+
* not covered by {@link NavigationItem}.
68+
*/
69+
public void colorNavigationViewItemIcon(@NonNull ImageView view) {
70+
withScheme(view, scheme -> {
71+
view.setImageTintList(buildColorStateList(
72+
new Pair<>(android.R.attr.state_selected, scheme.getOnSecondaryContainer()),
73+
new Pair<>(-android.R.attr.state_selected, scheme.getOnSurfaceVariant())
74+
));
75+
return view;
76+
});
77+
}
78+
79+
/**
80+
* The Notes app uses custom navigation view items because they have several features which are
81+
* not covered by {@link NavigationItem}.
82+
*/
83+
public void colorNavigationViewItemText(@NonNull TextView view) {
84+
withScheme(view, scheme -> {
85+
view.setTextColor(buildColorStateList(
86+
new Pair<>(android.R.attr.state_selected, scheme.getOnSecondaryContainer()),
87+
new Pair<>(-android.R.attr.state_selected, scheme.getOnSurfaceVariant())
88+
));
89+
return view;
90+
});
91+
}
92+
93+
/**
94+
* @deprecated should be replaced by {@link MaterialViewThemeUtils#themeToolbar(MaterialToolbar)}.
95+
*/
4096
@Deprecated(forRemoval = true)
4197
public void applyBrandToPrimaryToolbar(@NonNull AppBarLayout appBarLayout, @NonNull Toolbar toolbar, @ColorInt int color) {
4298
// FIXME Workaround for https://github.com/nextcloud/notes-android/issues/889
@@ -55,7 +111,9 @@ public void applyBrandToPrimaryToolbar(@NonNull AppBarLayout appBarLayout, @NonN
55111
}
56112
}
57113

58-
@Deprecated(forRemoval = true)
114+
/**
115+
* Colorizes only a specific part of a drawable
116+
*/
59117
public void colorLayerDrawable(@NonNull LayerDrawable check, @IdRes int areaToColor, @ColorInt int mainColor) {
60118
final var drawable = check.findDrawableByLayerId(areaToColor);
61119
if (drawable == null) {

app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
122122

123123
protected ItemAdapter adapter;
124124
private NavigationAdapter adapterCategories;
125+
@Nullable
125126
private MenuAdapter menuAdapter;
126127

127128
private SelectionTracker<Long> tracker;
@@ -351,7 +352,7 @@ public void onError(@NonNull Throwable t) {
351352
} else {
352353
startActivityForResult(menuItem.getIntent(), resultCode);
353354
}
354-
});
355+
}, nextAccount.getColor());
355356

356357
binding.navigationMenu.setAdapter(menuAdapter);
357358
} else {
@@ -596,6 +597,7 @@ public void applyBrand(int color) {
596597
final var util = BrandingUtil.of(color, this);
597598
util.material.themeFAB(activityBinding.fabCreate);
598599
util.platform.colorCircularProgressBar(activityBinding.progressCircular);
600+
util.platform.colorNavigationView(binding.navigationView);
599601
util.notes.applyBrandToPrimaryToolbar(activityBinding.appBar, activityBinding.searchToolbar, colorAccent);
600602

601603
binding.headerView.setBackgroundColor(color);
@@ -608,6 +610,9 @@ public void applyBrand(int color) {
608610

609611
adapter.applyBrand(color);
610612
adapterCategories.applyBrand(color);
613+
if (menuAdapter != null) {
614+
menuAdapter.applyBrand(color);
615+
}
611616
invalidateOptionsMenu();
612617
}
613618

app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuAdapter.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import android.view.LayoutInflater;
88
import android.view.ViewGroup;
99

10+
import androidx.annotation.ColorInt;
1011
import androidx.annotation.NonNull;
1112
import androidx.core.util.Consumer;
1213
import androidx.recyclerview.widget.RecyclerView;
@@ -17,6 +18,7 @@
1718
import it.niedermann.owncloud.notes.FormattingHelpActivity;
1819
import it.niedermann.owncloud.notes.R;
1920
import it.niedermann.owncloud.notes.about.AboutActivity;
21+
import it.niedermann.owncloud.notes.branding.BrandingUtil;
2022
import it.niedermann.owncloud.notes.databinding.ItemNavigationBinding;
2123
import it.niedermann.owncloud.notes.persistence.entity.Account;
2224
import it.niedermann.owncloud.notes.preferences.PreferencesActivity;
@@ -25,20 +27,28 @@ public class MenuAdapter extends RecyclerView.Adapter<MenuViewHolder> {
2527

2628
@NonNull
2729
private final MenuItem[] menuItems;
30+
@ColorInt
31+
private int color;
2832
@NonNull
2933
private final Consumer<MenuItem> onClick;
3034

31-
public MenuAdapter(@NonNull Context context, @NonNull Account account, int settingsRequestCode, @NonNull Consumer<MenuItem> onClick) {
35+
public MenuAdapter(@NonNull Context context, @NonNull Account account, int settingsRequestCode, @NonNull Consumer<MenuItem> onClick, @ColorInt int color) {
3236
this.menuItems = new MenuItem[]{
3337
new MenuItem(new Intent(context, FormattingHelpActivity.class), R.string.action_formatting_help, R.drawable.ic_baseline_help_outline_24),
3438
new MenuItem(generateTrashbinIntent(context, account), R.string.action_trashbin, R.drawable.ic_delete_grey600_24dp),
3539
new MenuItem(new Intent(context, PreferencesActivity.class), settingsRequestCode, R.string.action_settings, R.drawable.ic_settings_grey600_24dp),
3640
new MenuItem(new Intent(context, AboutActivity.class), R.string.simple_about, R.drawable.ic_info_outline_grey600_24dp)
3741
};
3842
this.onClick = onClick;
43+
this.color = color;
3944
setHasStableIds(true);
4045
}
4146

47+
public void applyBrand(int color) {
48+
this.color = color;
49+
notifyDataSetChanged();
50+
}
51+
4252
@Override
4353
public long getItemId(int position) {
4454
return position;
@@ -52,7 +62,7 @@ public MenuViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType
5262

5363
@Override
5464
public void onBindViewHolder(@NonNull MenuViewHolder holder, int position) {
55-
holder.bind(menuItems[position], onClick);
65+
holder.bind(menuItems[position], color, onClick);
5666
}
5767

5868
public void updateAccount(@NonNull Context context, @NonNull Account account) {

app/src/main/java/it/niedermann/owncloud/notes/main/menu/MenuViewHolder.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22

33
import android.content.Context;
44

5+
import androidx.annotation.ColorInt;
56
import androidx.annotation.NonNull;
67
import androidx.core.content.ContextCompat;
78
import androidx.core.util.Consumer;
89
import androidx.recyclerview.widget.RecyclerView;
910

1011
import it.niedermann.owncloud.notes.R;
12+
import it.niedermann.owncloud.notes.branding.BrandingUtil;
1113
import it.niedermann.owncloud.notes.databinding.ItemNavigationBinding;
1214

1315
import static android.view.View.GONE;
@@ -21,11 +23,19 @@ public MenuViewHolder(@NonNull ItemNavigationBinding binding) {
2123
this.binding = binding;
2224
}
2325

24-
public void bind(@NonNull MenuItem menuItem, @NonNull Consumer<MenuItem> onClick) {
26+
public void bind(@NonNull MenuItem menuItem, @ColorInt int color, @NonNull Consumer<MenuItem> onClick) {
2527
@NonNull Context context = itemView.getContext();
26-
binding.navigationItemLabel.setText(context.getString(menuItem.getLabelResource()));
28+
2729
binding.navigationItemIcon.setImageDrawable(ContextCompat.getDrawable(context, menuItem.getDrawableResource()));
30+
binding.navigationItemLabel.setText(context.getString(menuItem.getLabelResource()));
2831
binding.navigationItemCount.setVisibility(GONE);
2932
binding.getRoot().setOnClickListener((v) -> onClick.accept(menuItem));
33+
34+
final var util = BrandingUtil.of(color, binding.getRoot().getContext());
35+
36+
util.notes.colorNavigationViewItem(binding.getRoot());
37+
util.notes.colorNavigationViewItemIcon(binding.navigationItemIcon);
38+
util.notes.colorNavigationViewItemText(binding.navigationItemCount);
39+
util.notes.colorNavigationViewItemText(binding.navigationItemLabel);
3040
}
3141
}

app/src/main/java/it/niedermann/owncloud/notes/main/navigation/NavigationAdapter.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationViewHolder
3838
@DrawableRes
3939
public static final int ICON_SUB_MULTIPLE = R.drawable.ic_create_new_folder_grey600_18dp;
4040

41-
public void applyBrand(int color) {
42-
final var util = BrandingUtil.of(color, context);
43-
this.color = util.notes.getOnPrimaryContainer(context);
44-
notifyDataSetChanged();
45-
}
46-
4741
@NonNull
4842
private List<NavigationItem> items = new ArrayList<>();
4943
private String selectedItem = null;
@@ -52,11 +46,15 @@ public void applyBrand(int color) {
5246

5347
public NavigationAdapter(@NonNull Context context, @NonNull NavigationClickListener navigationClickListener) {
5448
this.context = context;
55-
final var util = BrandingUtil.of(BrandingUtil.readBrandMainColor(context), context);
56-
this.color = util.notes.getOnPrimaryContainer(context);
49+
this.color = BrandingUtil.readBrandMainColor(context);
5750
this.navigationClickListener = navigationClickListener;
5851
}
5952

53+
public void applyBrand(int color) {
54+
this.color = color;
55+
notifyDataSetChanged();
56+
}
57+
6058
@NonNull
6159
@Override
6260
public NavigationViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

app/src/main/java/it/niedermann/owncloud/notes/main/navigation/NavigationViewHolder.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import androidx.recyclerview.widget.RecyclerView;
1515

1616
import it.niedermann.owncloud.notes.R;
17+
import it.niedermann.owncloud.notes.branding.BrandingUtil;
1718
import it.niedermann.owncloud.notes.databinding.ItemNavigationBinding;
1819
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
1920

@@ -41,7 +42,7 @@ class NavigationViewHolder extends RecyclerView.ViewHolder {
4142
itemView.setOnClickListener(view -> navigationClickListener.onItemClick(currentItem));
4243
}
4344

44-
public void bind(@NonNull NavigationItem item, @ColorInt int mainColor, String selectedItem) {
45+
public void bind(@NonNull NavigationItem item, @ColorInt int color, String selectedItem) {
4546
currentItem = item;
4647
final boolean isSelected = item.id.equals(selectedItem);
4748
name.setText(NoteUtil.extendCategory(item.label));
@@ -53,15 +54,17 @@ public void bind(@NonNull NavigationItem item, @ColorInt int mainColor, String s
5354
} else {
5455
icon.setVisibility(View.GONE);
5556
}
56-
final int textColor = isSelected ? mainColor : view.getResources().getColor(R.color.fg_default);
5757

58-
name.setTextColor(textColor);
59-
count.setTextColor(textColor);
60-
icon.setColorFilter(isSelected ? textColor : 0);
58+
final var util = BrandingUtil.of(color, itemView.getContext());
59+
60+
util.notes.colorNavigationViewItem(view);
61+
util.notes.colorNavigationViewItemIcon(icon);
62+
util.notes.colorNavigationViewItemText(name);
63+
util.notes.colorNavigationViewItemText(count);
6164

6265
view.setSelected(isSelected);
6366

64-
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
67+
final var params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
6568
params.leftMargin = item.icon == NavigationAdapter.ICON_SUB_FOLDER || item.icon == NavigationAdapter.ICON_SUB_MULTIPLE
6669
? view.getResources().getDimensionPixelSize(R.dimen.spacer_3x)
6770
: 0;

app/src/main/res/layout/drawer_layout.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
android:layout_height="match_parent" />
1515

1616
<com.google.android.material.navigation.NavigationView
17+
android:id="@+id/navigation_view"
1718
android:layout_width="wrap_content"
1819
android:layout_height="match_parent"
1920
android:layout_gravity="start"

0 commit comments

Comments
 (0)