package mobi.monaca.framework.nativeui.container; import static mobi.monaca.framework.nativeui.UIUtil.buildColor; import static mobi.monaca.framework.nativeui.UIUtil.buildOpacity; import static mobi.monaca.framework.nativeui.UIUtil.updateJSONObject; import java.io.IOException; import java.util.ArrayList; import mobi.monaca.framework.nativeui.DefaultStyleJSON; import mobi.monaca.framework.nativeui.UIContext; import mobi.monaca.framework.nativeui.UIValidator; import mobi.monaca.framework.nativeui.component.BackButtonComponent; import mobi.monaca.framework.nativeui.component.ButtonComponent; import mobi.monaca.framework.nativeui.component.LabelComponent; import mobi.monaca.framework.nativeui.component.SearchBoxComponent; import mobi.monaca.framework.nativeui.component.SegmentComponent; import mobi.monaca.framework.nativeui.component.ToolbarBackgroundDrawable; import mobi.monaca.framework.nativeui.component.ToolbarComponent; import mobi.monaca.framework.nativeui.component.view.ContainerShadowView; import mobi.monaca.framework.nativeui.exception.ConversionException; import mobi.monaca.framework.nativeui.exception.DuplicateIDException; import mobi.monaca.framework.nativeui.exception.InvalidValueException; import mobi.monaca.framework.nativeui.exception.KeyNotValidException; import mobi.monaca.framework.nativeui.exception.NativeUIException; import mobi.monaca.framework.nativeui.exception.NativeUIIOException; import mobi.monaca.framework.nativeui.exception.RequiredKeyNotFoundException; import mobi.monaca.framework.nativeui.exception.ValueNotInRangeException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.graphics.Bitmap; import android.graphics.ColorFilter; import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.drawable.Drawable; import android.view.View; import android.view.animation.AlphaAnimation; import android.view.animation.Animation; import android.view.animation.LinearInterpolator; public class ToolbarContainer extends Container { protected ToolbarContainerView view; protected ToolbarComponent left, center, right; protected AlphaAnimation animation = null; private ContainerShadowView shadowView; protected static String[] toolbarValidKeys = { "container", "style", "iosStyle", "androidStyle", "id", "left", "center", "right" }; protected static String[] styleValidKeys = { "visibility", "disable", "opacity", "shadowOpacity", "backgroundColor", "title", "subtitle", "titleColor", "subtitleColor", "titleFontScale", "subtitleFontScale", "titleImage", "iosBarStyle", }; protected static String[] validComponents = { "backButton", "button", "searchBox", "label", "segment" }; public ToolbarContainer(UIContext context, JSONObject toolbarJSON, boolean isTop) throws KeyNotValidException, DuplicateIDException, NativeUIIOException, NativeUIException, JSONException { super(context, toolbarJSON); UIValidator.validateKey(context, "Toolbar's style", style, styleValidKeys); view = new ToolbarContainerView(context, isTop); shadowView = new ContainerShadowView(context, isTop); buildChildren(); style(); } private void buildChildren() throws NativeUIException, JSONException { JSONArray left = getComponentJSON().optJSONArray("left"); if (left != null) { ArrayList<ToolbarComponent> leftComponents = buildComponents("left", left); view.setLeftView(leftComponents); } JSONArray right = getComponentJSON().optJSONArray("right"); if (right != null) { ArrayList<ToolbarComponent> rightComponents = buildComponents("right", right); view.setRightView(rightComponents); } JSONArray center = getComponentJSON().optJSONArray("center"); if (center != null) { ArrayList<ToolbarComponent> centerComponents = buildComponents("center", center); boolean shouldExpandItemWidth = false; if ((left == null && right == null) || (left == null && right.length() == 0) || (left.length() == 0 && right == null) || (left.length() == 0 && right.length() == 0)) { shouldExpandItemWidth = true; } view.setCenterView(centerComponents, shouldExpandItemWidth); } } private ArrayList<ToolbarComponent> buildComponents(String position, JSONArray componentsJSONArray) throws NativeUIException, JSONException { ArrayList<ToolbarComponent> leftComponents = new ArrayList<ToolbarComponent>(); ToolbarComponent component; JSONObject componentJSON; for (int i = 0; i < componentsJSONArray.length(); i++) { componentJSON = componentsJSONArray.optJSONObject(i); component = buildComponent(position, componentJSON); leftComponents.add(component); } return leftComponents; } private ToolbarComponent buildComponent(String positioin, JSONObject childJSON) throws NativeUIException, JSONException{ String componentType = childJSON.optString("component"); if(componentType == null){ throw new RequiredKeyNotFoundException(getComponentName() + positioin, "component"); } if (componentType.equals("backButton")) { return new BackButtonComponent(uiContext, childJSON); } else if (componentType.equals("button")) { return new ButtonComponent(uiContext, childJSON); } else if (componentType.equals("searchBox")) { return new SearchBoxComponent(uiContext, childJSON); } else if (componentType.equals("label")) { return new LabelComponent(uiContext, childJSON); } else if (componentType.equals("segment")) { return new SegmentComponent(uiContext, childJSON); } else { InvalidValueException exception = new InvalidValueException("Toolbar", "component", componentType, validComponents); throw exception; } } public void updateStyle(JSONObject update) throws NativeUIException { updateJSONObject(style, update); style(); } public View getView() { return view; } /** * visibility: [bool] (default: true) opacity: 0.0-1.0 [float] (default: * 1.0) backgroundColor: #000000 [string] (default: undefined) position : * "fixed" | "scroll" (default: "fixed") => androidだと無理ぽい title : [string] * (default : "") (このスタイルが指定された場合、center属性は無視される) titleImage : [string] * (default : "") このスタイルが指定された時、center属性は無視) * * @throws NativeUIException */ protected void style() throws NativeUIException { String toolbarOpacityString = "1.0"; float toolbarOpacity = 1.0f; if(style.has("opacity")){ toolbarOpacityString = style.optString("opacity"); } try{ toolbarOpacity = Float.parseFloat(toolbarOpacityString); if(toolbarOpacity < 0.0 || toolbarOpacity > 1.0 ){ throw new ValueNotInRangeException(getComponentName() + "style", "opacity", toolbarOpacityString, "[0.0-1.0]"); } }catch(NumberFormatException e){ ConversionException conversionException = new ConversionException(getComponentName() + " style", "opacity", toolbarOpacityString, "Float"); throw conversionException; } if (isTransparent() && view.getVisibility() != (style.optBoolean("visibility", true) ? View.VISIBLE : View.INVISIBLE)) { if (animation != null) { // animation.cancel(); //TODO only available in Android 4.0 } animation = style.optBoolean("visibility", true) ? new AlphaAnimation(0f, 1.0f) : new AlphaAnimation(1.0f, 0f); animation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { view.setVisibility(style.optBoolean("visibility", true) ? View.VISIBLE : View.INVISIBLE); ToolbarContainer.this.animation = null; } }); animation.setInterpolator(new LinearInterpolator()); animation.setDuration(200); // cause GC to prevent "stop the world" on animation. System.gc(); view.startAnimation(animation); } else { view.setVisibility(style.optBoolean("visibility", true) ? View.VISIBLE : View.GONE); } // titleColor String titleColorString = style.optString("titleColor", "#ffffff"); try { view.setTitleColor(titleColorString); } catch (IllegalArgumentException e) { ConversionException conversionException = new ConversionException(getComponentName() + " style", "titleColor", titleColorString, "Color"); throw conversionException; } // subtitleColor String subtitleColorString = style.optString("subtitleColor", "#ffffff"); try { view.setSubtitleColor(subtitleColorString); } catch (IllegalArgumentException e) { ConversionException conversionException = new ConversionException(getComponentName() + " style", "subtitleColor", subtitleColorString, "Color"); throw conversionException; } // titleFontScale String titleFontScaleString = style.optString("titleFontScale", ""); try{ view.setTitleFontScale(titleFontScaleString); }catch(NumberFormatException e){ ConversionException conversionException = new ConversionException(getComponentName() + " style", "titleFontScale", titleFontScaleString, "Float"); throw conversionException; } // subtitleFontScale String subtitleFontScaleString = style.optString("subtitleFontScale", ""); try{ view.setSubitleFontScale(subtitleFontScaleString); }catch(NumberFormatException e){ ConversionException conversionException = new ConversionException(getComponentName() + " style", "subtitleFontScale", subtitleFontScaleString, "Float"); throw conversionException; } String titleImagePath = style.optString("titleImage", ""); Bitmap titleImage; try { titleImage = titleImagePath.equals("") ? null : uiContext.readScaledBitmap(titleImagePath); view.setTitleSubtitle(style.optString("title"), style.optString("subtitle"), titleImage); } catch (IOException e) { NativeUIIOException exception = new NativeUIIOException(getComponentName() + " style", "titleImage", titleImagePath, e.getMessage()); throw exception; } String backgroundColorString = style.optString("backgroundColor", "#000000"); try { ColorFilter filter = new PorterDuffColorFilter(buildColor(backgroundColorString), PorterDuff.Mode.SCREEN); Drawable toolbarBackground = new ToolbarBackgroundDrawable(uiContext); toolbarBackground.setColorFilter(filter); toolbarBackground.setAlpha(buildOpacity(style.optDouble("opacity", 1.0))); view.getContentView().setBackgroundDrawable(toolbarBackground); } catch (IllegalArgumentException e) { ConversionException conversionException = new ConversionException(getComponentName() + " style", "backgroundColor", backgroundColorString, "Color"); throw conversionException; } String shadowOpacityString = "0.3"; if(style.has("shadowOpacity")){ shadowOpacityString = style.optString("shadowOpacity"); } try{ double shadowOpacity = Float.parseFloat(shadowOpacityString); if(shadowOpacity < 0.0 || shadowOpacity > 1.0){ throw new ValueNotInRangeException(getComponentName() + " style", "shadowOpacity", shadowOpacityString, "[0.0-1.0]"); } double relativeShadowOpacity = toolbarOpacity * shadowOpacity; shadowView.getBackground().setAlpha(buildOpacity(relativeShadowOpacity)); }catch(NumberFormatException e){ ConversionException conversionException = new ConversionException(getComponentName() + " style", "shadowOpacity", shadowOpacityString, "Float"); throw conversionException; } view.setBackgroundDrawable(null); view.setBackgroundColor(0); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { view.requestFocus(); } }); } @Override protected void finalize() throws Throwable { super.finalize(); if (view != null && view.getContentView() != null) { view.getContentView().setBackgroundDrawable(null); } } public boolean isTransparent() { double opacity = style.optDouble("opacity", 1.0); return opacity <= 0.999; } public View getShadowView() { return shadowView; } @Override public String getComponentName() { return "Toolbar"; } @Override public JSONObject getDefaultStyle() { return DefaultStyleJSON.toolbar(); } @Override public String[] getValidKeys() { return toolbarValidKeys; } }