/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ package com.facebook.react.views.toolbar; import javax.annotation.Nullable; import java.util.Map; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Color; import android.util.LayoutDirection; import android.view.MenuItem; import android.view.View; import com.facebook.react.R; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.PixelUtil; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.UIManagerModule; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.views.toolbar.events.ToolbarClickEvent; /** * Manages instances of ReactToolbar. */ public class ReactToolbarManager extends ViewGroupManager<ReactToolbar> { private static final String REACT_CLASS = "ToolbarAndroid"; @Override public String getName() { return REACT_CLASS; } @Override protected ReactToolbar createViewInstance(ThemedReactContext reactContext) { return new ReactToolbar(reactContext); } @ReactProp(name = "logo") public void setLogo(ReactToolbar view, @Nullable ReadableMap logo) { view.setLogoSource(logo); } @ReactProp(name = "navIcon") public void setNavIcon(ReactToolbar view, @Nullable ReadableMap navIcon) { view.setNavIconSource(navIcon); } @ReactProp(name = "overflowIcon") public void setOverflowIcon(ReactToolbar view, @Nullable ReadableMap overflowIcon) { view.setOverflowIconSource(overflowIcon); } @ReactProp(name = "rtl") public void setRtl(ReactToolbar view, boolean rtl) { view.setLayoutDirection(rtl ? LayoutDirection.RTL : LayoutDirection.LTR); } @ReactProp(name = "subtitle") public void setSubtitle(ReactToolbar view, @Nullable String subtitle) { view.setSubtitle(subtitle); } @ReactProp(name = "subtitleColor", customType = "Color") public void setSubtitleColor(ReactToolbar view, @Nullable Integer subtitleColor) { int[] defaultColors = getDefaultColors(view.getContext()); if (subtitleColor != null) { view.setSubtitleTextColor(subtitleColor); } else { view.setSubtitleTextColor(defaultColors[1]); } } @ReactProp(name = "title") public void setTitle(ReactToolbar view, @Nullable String title) { view.setTitle(title); } @ReactProp(name = "titleColor", customType = "Color") public void setTitleColor(ReactToolbar view, @Nullable Integer titleColor) { int[] defaultColors = getDefaultColors(view.getContext()); if (titleColor != null) { view.setTitleTextColor(titleColor); } else { view.setTitleTextColor(defaultColors[0]); } } @ReactProp(name = "contentInsetStart", defaultFloat = Float.NaN) public void setContentInsetStart(ReactToolbar view, float insetStart) { int inset = Float.isNaN(insetStart) ? getDefaultContentInsets(view.getContext())[0] : Math.round(PixelUtil.toPixelFromDIP(insetStart)); view.setContentInsetsRelative(inset, view.getContentInsetEnd()); } @ReactProp(name = "contentInsetEnd", defaultFloat = Float.NaN) public void setContentInsetEnd(ReactToolbar view, float insetEnd) { int inset = Float.isNaN(insetEnd) ? getDefaultContentInsets(view.getContext())[1] : Math.round(PixelUtil.toPixelFromDIP(insetEnd)); view.setContentInsetsRelative(view.getContentInsetStart(), inset); } @ReactProp(name = "nativeActions") public void setActions(ReactToolbar view, @Nullable ReadableArray actions) { view.setActions(actions); } @Override protected void addEventEmitters(final ThemedReactContext reactContext, final ReactToolbar view) { final EventDispatcher mEventDispatcher = reactContext.getNativeModule(UIManagerModule.class) .getEventDispatcher(); view.setNavigationOnClickListener( new View.OnClickListener() { @Override public void onClick(View v) { mEventDispatcher.dispatchEvent( new ToolbarClickEvent(view.getId(), -1)); } }); view.setOnMenuItemClickListener( new ReactToolbar.OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem menuItem) { mEventDispatcher.dispatchEvent( new ToolbarClickEvent( view.getId(), menuItem.getOrder())); return true; } }); } @Nullable @Override public Map<String, Object> getExportedViewConstants() { return MapBuilder.<String, Object>of( "ShowAsAction", MapBuilder.of( "never", MenuItem.SHOW_AS_ACTION_NEVER, "always", MenuItem.SHOW_AS_ACTION_ALWAYS, "ifRoom", MenuItem.SHOW_AS_ACTION_IF_ROOM)); } @Override public boolean needsCustomLayoutForChildren() { return true; } private int[] getDefaultContentInsets(Context context) { Resources.Theme theme = context.getTheme(); TypedArray toolbarStyle = null; TypedArray contentInsets = null; try { toolbarStyle = theme .obtainStyledAttributes(new int[]{R.attr.toolbarStyle}); int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); contentInsets = theme.obtainStyledAttributes( toolbarStyleResId, new int[]{ R.attr.contentInsetStart, R.attr.contentInsetEnd, }); int contentInsetStart = contentInsets.getDimensionPixelSize(0, 0); int contentInsetEnd = contentInsets.getDimensionPixelSize(1, 0); return new int[] {contentInsetStart, contentInsetEnd}; } finally { recycleQuietly(toolbarStyle); recycleQuietly(contentInsets); } } private static int[] getDefaultColors(Context context) { Resources.Theme theme = context.getTheme(); TypedArray toolbarStyle = null; TypedArray textAppearances = null; TypedArray titleTextAppearance = null; TypedArray subtitleTextAppearance = null; try { toolbarStyle = theme .obtainStyledAttributes(new int[]{R.attr.toolbarStyle}); int toolbarStyleResId = toolbarStyle.getResourceId(0, 0); textAppearances = theme.obtainStyledAttributes( toolbarStyleResId, new int[]{ R.attr.titleTextAppearance, R.attr.subtitleTextAppearance, }); int titleTextAppearanceResId = textAppearances.getResourceId(0, 0); int subtitleTextAppearanceResId = textAppearances.getResourceId(1, 0); titleTextAppearance = theme .obtainStyledAttributes(titleTextAppearanceResId, new int[]{android.R.attr.textColor}); subtitleTextAppearance = theme .obtainStyledAttributes(subtitleTextAppearanceResId, new int[]{android.R.attr.textColor}); int titleTextColor = titleTextAppearance.getColor(0, Color.BLACK); int subtitleTextColor = subtitleTextAppearance.getColor(0, Color.BLACK); return new int[] {titleTextColor, subtitleTextColor}; } finally { recycleQuietly(toolbarStyle); recycleQuietly(textAppearances); recycleQuietly(titleTextAppearance); recycleQuietly(subtitleTextAppearance); } } private static void recycleQuietly(@Nullable TypedArray style) { if (style != null) { style.recycle(); } } }