Commit c0cabd21 authored by Susan Rati Lane's avatar Susan Rati Lane Committed by Jeffrey I. Schiller

Implement toggle switch control

This is a toggle switch component. Functionally, it behaves the same as a checkbox: the ON state is equivalent to checked.

Since iOS does not have a checkbox and only offers toggle switches, this component paves the way for an on/off component that is shared by both Android and iOS.

The toggle switch is a 2-color control, which means that there are 4 configurable colors, 2 for on and 2 for off.
parent 95398173
......@@ -134,6 +134,12 @@ public interface Images extends Resources {
@Source("com/google/appinventor/images/checkbox.png")
ImageResource checkbox();
/**
* Designer palette item: checkbox component
*/
@Source("com/google/appinventor/images/switch.png")
ImageResource toggleswitch();
/**
* Designer palette item: DatePicker Component
*/
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Copyright 2018 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.editor.simple.components;
import static com.google.appinventor.client.Ode.MESSAGES;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Widget;
/**
* Mock CheckBox component.
* Mock CheckBox component, inherited from MockToggleBase
*
* @author lizlooney@google.com (Liz Looney)
* @author lizlooney@google.com (Liz Looney), srlane@mit.edu (Susan Rati Lane)
*/
public final class MockCheckBox extends MockWrapper {
public final class MockCheckBox extends MockToggleBase<CheckBox> {
/**
* Component type name.
*/
public static final String TYPE = "CheckBox";
// GWT checkbox widget used to mock a Simple CheckBox
private CheckBox checkboxWidget;
/**
* Creates a new MockCheckbox component.
*
......@@ -34,10 +30,8 @@ public final class MockCheckBox extends MockWrapper {
*/
public MockCheckBox(SimpleEditor editor) {
super(editor, TYPE, images.checkbox());
// Initialize mock checkbox UI
checkboxWidget = new CheckBox();
initWrapper(checkboxWidget);
toggleWidget = new CheckBox();
initWrapper(toggleWidget);
}
/**
......@@ -57,132 +51,33 @@ public final class MockCheckBox extends MockWrapper {
}
}
@Override
protected Widget createClonedWidget() {
return new ClonedCheckBox(checkboxWidget);
}
@Override
public void onCreateFromPalette() {
// Change checkbox caption to component name
changeProperty(PROPERTY_NAME_TEXT, MESSAGES.textPropertyValue(getName()));
}
/*
* Sets the checkbox's BackgroundColor property to a new value.
*/
private void setBackgroundColorProperty(String text) {
if (MockComponentsUtil.isDefaultColor(text)) {
text = "&HFFFFFFFF"; // white
}
MockComponentsUtil.setWidgetBackgroundColor(checkboxWidget, text);
}
/*
* Sets the checkbox's Enabled property to a new value.
*/
private void setEnabledProperty(String text) {
MockComponentsUtil.setEnabled(this, text);
}
/*
* Sets the checkbox's FontBold property to a new value.
*/
private void setFontBoldProperty(String text) {
MockComponentsUtil.setWidgetFontBold(checkboxWidget, text);
updatePreferredSize();
}
/*
* Sets the checkbox's FontItalic property to a new value.
*/
private void setFontItalicProperty(String text) {
MockComponentsUtil.setWidgetFontItalic(checkboxWidget, text);
updatePreferredSize();
}
@Override
int getHeightHint() {
int hint = super.getHeightHint();
if (hint == MockVisibleComponent.LENGTH_PREFERRED) {
float height = Float.parseFloat(getPropertyValue(MockVisibleComponent.PROPERTY_NAME_FONTSIZE));
return Math.round(height);
} else {
return hint;
}
}
/*
* Sets the checkbox's FontSize property to a new value.
*/
private void setFontSizeProperty(String text) {
MockComponentsUtil.setWidgetFontSize(checkboxWidget, text);
updatePreferredSize();
}
/*
* Sets the checkbox's FontTypeface property to a new value.
*/
private void setFontTypefaceProperty(String text) {
MockComponentsUtil.setWidgetFontTypeface(checkboxWidget, text);
updatePreferredSize();
return new ClonedCheckBox(toggleWidget);
}
/*
* Sets the checkbox's Text property to a new value.
*/
private void setTextProperty(String text) {
checkboxWidget.setText(text);
protected void setTextProperty(String text) {
toggleWidget.setText(text);
updatePreferredSize();
}
/*
* Sets the checkbox's TextColor property to a new value.
*/
private void setTextColorProperty(String text) {
if (MockComponentsUtil.isDefaultColor(text)) {
text = "&HFF000000"; // black
}
MockComponentsUtil.setWidgetTextColor(checkboxWidget, text);
}
/*
* Sets the checkbox's Checked property to a new value.
*/
private void setCheckedProperty(String text) {
checkboxWidget.setChecked(Boolean.parseBoolean(text));
toggleWidget.setChecked(Boolean.parseBoolean(text));
}
// PropertyChangeListener implementation
@Override
public void onPropertyChange(String propertyName, String newValue) {
super.onPropertyChange(propertyName, newValue);
// Apply changed properties to the mock component
if (propertyName.equals(PROPERTY_NAME_BACKGROUNDCOLOR)) {
setBackgroundColorProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_ENABLED)) {
setEnabledProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_FONTBOLD)) {
setFontBoldProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTITALIC)) {
setFontItalicProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTSIZE)) {
setFontSizeProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTTYPEFACE)) {
setFontTypefaceProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TEXT)) {
setTextProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TEXTCOLOR)) {
setTextColorProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_CHECKED)) {
if (propertyName.equals(PROPERTY_NAME_CHECKED)) {
setCheckedProperty(newValue);
refreshForm();
}
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2018 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.editor.simple.components;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.appinventor.client.editor.simple.components.utils.SVGPanel;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.InlineHTML;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Widget;
/**
* Mock Switch component, inherited from MockToggleBase
*
* @author srlane@mit.edu (Susan Rati Lane)
*/
public final class MockSwitch extends MockToggleBase<HorizontalPanel> {
/**
* Component type name.
*/
public static final String TYPE = "Switch";
protected final HorizontalPanel panel;
public Boolean checked = false; // the "on" property of the switch is equivalent to "checked"
public String thumbColorActive = "white";
public String thumbColorInactive = "gray";
public String trackColorActive = "lime";
public String trackColorInactive = "lightgray";
public InlineHTML switchLabel;
public SVGPanel switchGraphic;
public Boolean isInitialized = false;
/**
* Creates a new MockSwitch component.
*
* @param editor editor of source file the component belongs to
*/
public MockSwitch(SimpleEditor editor) {
super(editor, TYPE, images.toggleswitch());
panel = new HorizontalPanel();
switchLabel = new InlineHTML();
panel.add(switchLabel);
toggleWidget = panel;
isInitialized = false;
initWrapper(toggleWidget);
}
/**
* Class that extends Widget so we can use a protected constructor.
*
* <p/>The purpose of this class is to create a clone of the Switch
* passed to the constructor. It will be used to determine the preferred size
* of the Switch, without having the size constrained by its parent,
* since the cloned Switch won't have a parent.
*/
static class ClonedSwitch extends InlineHTML {
ClonedSwitch(HorizontalPanel ptb) {
super(DOM.clone(ptb.getElement(), true));
}
}
@Override
protected Widget createClonedWidget() {
return new ClonedSwitch(toggleWidget);
}
/**
* Draw the SVG graphic of the toggle switch. It can be drawn in either checked or
* unchecked positions, each with their own colors.
*
*/
private void paintSwitch() {
if (isInitialized) {
panel.remove(switchGraphic);
} else {
isInitialized = true;
}
switchGraphic = new SVGPanel();
int switchHeight = Math.round(Float.parseFloat(getPropertyValue(MockVisibleComponent.PROPERTY_NAME_FONTSIZE)));
int switchWidth = (int) Math.round(switchHeight * 2);
switchGraphic.setWidth(switchWidth + "px");
switchGraphic.setHeight(switchHeight + "px");
switchGraphic.setInnerSVG("<rect x=\"0\" y=\"0\" rx=\"" +
switchHeight/2 + "\" yx=\"" + switchWidth/2 + "\" stroke-width=\"1\" stroke=\"black\"" +
"height=\"" + switchHeight + "\" width=\"" + switchWidth + "\" fill=\"" + (checked? trackColorActive : trackColorInactive) + "\" />" +
"<circle cx=\"" + (checked? switchWidth - switchHeight/2: switchHeight/2) + "\" fill=\"" + (checked? thumbColorActive : thumbColorInactive) + "\" " +
"cy=\"" + (switchHeight/2) + "\" r=\"" + (switchHeight/2 - 1) + "\"/>");
panel.add(switchGraphic);
panel.setCellWidth(switchGraphic, switchWidth + "px");
panel.setCellHorizontalAlignment(switchGraphic, HasHorizontalAlignment.ALIGN_RIGHT);
toggleWidget = panel;
refreshForm();
}
/**
* Set thumb color for switch in checked state
* Thumb color is the color the color of the button that toggles back and forth
*
*/
private void setThumbColorActiveProperty(String text) {
thumbColorActive = MockComponentsUtil.getColor(text).toString();
if (checked) {
DOM.setStyleAttribute(toggleWidget.getWidget(1).getElement().getFirstChildElement().getNextSiblingElement(),
"fill", thumbColorActive);
}
}
/**
* Set thumb color for switch in UNhecked state
* Thumb color is the color the color of the button that toggles back and forth
*
*/
private void setThumbColorInactiveProperty(String text) {
thumbColorInactive = MockComponentsUtil.getColor(text).toString();
if (!checked) {
DOM.setStyleAttribute(toggleWidget.getWidget(1).getElement().getFirstChildElement().getNextSiblingElement(),
"fill", thumbColorInactive);
}
}
/**
* Set track color for switch in checked state
* Track color is the color of the track that the toggle button slides back and forth along
*
*/
private void setTrackColorActiveProperty(String text) {
trackColorActive = MockComponentsUtil.getColor(text).toString();
if (checked) {
DOM.setStyleAttribute(toggleWidget.getWidget(1).getElement().getFirstChildElement(), "fill",
trackColorActive);
}
}
/**
* Set track color for switch in UNchecked state
* Track color is the color of the track that the toggle button slides back and forth along
*
*/
private void setTrackColorInactiveProperty(String text) {
trackColorInactive = MockComponentsUtil.getColor(text).toString();
if (!checked) {
DOM.setStyleAttribute(toggleWidget.getWidget(1).getElement().getFirstChildElement(), "fill",
trackColorInactive);
}
}
/*
* Sets the switch's Checked property to a new value.
*/
private void setOnProperty(String text) {
checked = Boolean.parseBoolean(text);
paintSwitch();
}
/*
* Sets the switch's Text property to a new value.
*/
protected void setTextProperty(String text) {
panel.remove(switchLabel);
switchLabel.setText(text);
panel.insert(switchLabel, 0);
toggleWidget = panel;
updatePreferredSize();
}
@Override
protected void setFontSizeProperty(String text) {
MockComponentsUtil.setWidgetFontSize(toggleWidget.getWidget(0), text);
updatePreferredSize();
}
@Override
protected void setFontTypefaceProperty(String text) {
MockComponentsUtil.setWidgetFontTypeface(toggleWidget.getWidget(0), text);
updatePreferredSize();
}
@Override
public void onPropertyChange(String propertyName, String newValue) {
super.onPropertyChange(propertyName, newValue);
// Apply changed properties to the mock component
if (propertyName.equals(PROPERTY_NAME_ON)) {
setOnProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_THUMBCOLORACTIVE)) {
setThumbColorActiveProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_THUMBCOLORINACTIVE)) {
setThumbColorInactiveProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TRACKCOLORACTIVE)) {
setTrackColorActiveProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TRACKCOLORINACTIVE)) {
setTrackColorInactiveProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_HEIGHT)) {
paintSwitch();
refreshForm();
}
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2016-2018 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.client.editor.simple.components;
import com.google.appinventor.client.editor.simple.SimpleEditor;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.ui.Widget;
import static com.google.appinventor.client.Ode.MESSAGES;
/**
* Abstract class for on/off toggle components, e.g. Checkbox and Switch
*
* @author srlane@mit.edu (Susan Rati Lane)
*/
abstract class MockToggleBase<T extends Widget> extends MockWrapper {
// Set toggle widget in child classes
protected T toggleWidget;
public MockToggleBase(SimpleEditor editor, String type, ImageResource icon) {
super(editor, type, icon);
}
abstract protected Widget createClonedWidget();
@Override
public void onCreateFromPalette() {
// Change toggle caption to component name
changeProperty(PROPERTY_NAME_TEXT, MESSAGES.textPropertyValue(getName()));
}
/*
* Sets the toggle's BackgroundColor property to a new value.
*/
private void setBackgroundColorProperty(String text) {
if (MockComponentsUtil.isDefaultColor(text)) {
text = "&HFFFFFFFF"; // white
}
MockComponentsUtil.setWidgetBackgroundColor(toggleWidget, text);
}
/*
* Sets the toggle's Enabled property to a new value.
*/
private void setEnabledProperty(String text) {
MockComponentsUtil.setEnabled(this, text);
}
/*
* Sets the toggle's FontBold property to a new value.
*/
private void setFontBoldProperty(String text) {
MockComponentsUtil.setWidgetFontBold(toggleWidget, text);
updatePreferredSize();
}
/*
* Sets the toggle's FontItalic property to a new value.
*/
private void setFontItalicProperty(String text) {
MockComponentsUtil.setWidgetFontItalic(toggleWidget, text);
updatePreferredSize();
}
@Override
int getHeightHint() {
int hint = super.getHeightHint();
if (hint == MockVisibleComponent.LENGTH_PREFERRED) {
float height = Float.parseFloat(getPropertyValue(MockVisibleComponent.PROPERTY_NAME_FONTSIZE));
return Math.round(height);
} else {
return hint;
}
}
/*
* Sets the toggle's FontSize property to a new value.
*/
protected void setFontSizeProperty(String text) {
MockComponentsUtil.setWidgetFontSize(toggleWidget, text);
updatePreferredSize();
}
/*
* Sets the toggle's FontTypeface property to a new value.
*/
protected void setFontTypefaceProperty(String text) {
MockComponentsUtil.setWidgetFontTypeface(toggleWidget, text);
updatePreferredSize();
}
/*
* The toggle's set text must be implemented in child classes
*/
abstract void setTextProperty(String text);
/*
* Sets the toggle's TextColor property to a new value.
*/
private void setTextColorProperty(String text) {
if (MockComponentsUtil.isDefaultColor(text)) {
text = "&HFF000000"; // black
}
MockComponentsUtil.setWidgetTextColor(toggleWidget, text);
}
@Override
public void onPropertyChange(String propertyName, String newValue) {
super.onPropertyChange(propertyName, newValue);
// Apply changed properties to the mock component
if (propertyName.equals(PROPERTY_NAME_BACKGROUNDCOLOR)) {
setBackgroundColorProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_ENABLED)) {
setEnabledProperty(newValue);
} else if (propertyName.equals(PROPERTY_NAME_FONTBOLD)) {
setFontBoldProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTITALIC)) {
setFontItalicProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTSIZE)) {
setFontSizeProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_FONTTYPEFACE)) {
setFontTypefaceProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TEXT)) {
setTextProperty(newValue);
refreshForm();
} else if (propertyName.equals(PROPERTY_NAME_TEXTCOLOR)) {
setTextColorProperty(newValue);
}
}
}
......@@ -26,6 +26,10 @@ public abstract class MockVisibleComponent extends MockComponent {
protected static final String PROPERTY_NAME_BUTTONSHAPE= "Shape";
protected static final String PROPERTY_NAME_BACKGROUNDCOLOR = "BackgroundColor";
protected static final String PROPERTY_NAME_BACKGROUNDIMAGE = "BackgroundImage";
protected static final String PROPERTY_NAME_THUMBCOLORACTIVE = "ThumbColorActive";
protected static final String PROPERTY_NAME_THUMBCOLORINACTIVE = "ThumbColorInactive";
protected static final String PROPERTY_NAME_TRACKCOLORACTIVE = "TrackColorActive";
protected static final String PROPERTY_NAME_TRACKCOLORINACTIVE = "TrackColorInactive";
protected static final String PROPERTY_NAME_ENABLED = "Enabled";
protected static final String PROPERTY_NAME_FONTBOLD = "FontBold";
protected static final String PROPERTY_NAME_FONTITALIC = "FontItalic";
......@@ -36,6 +40,7 @@ public abstract class MockVisibleComponent extends MockComponent {
protected static final String PROPERTY_NAME_SHOW_FILTER_BAR = "ShowFilterBar";
protected static final String PROPERTY_NAME_TEXTCOLOR = "TextColor";
protected static final String PROPERTY_NAME_CHECKED = "Checked"; // checkbox and radio button
protected static final String PROPERTY_NAME_ON = "On"; // toggle switch
protected static final String PROPERTY_NAME_HINT = "Hint";
protected static final String PROPERTY_NAME_HTMLFORMAT = "HTMLFormat";
protected static final String PROPERTY_NAME_VISIBLE = "Visible";
......
......@@ -14,6 +14,7 @@ import com.google.appinventor.client.editor.simple.components.MockBall;
import com.google.appinventor.client.editor.simple.components.MockButton;
import com.google.appinventor.client.editor.simple.components.MockCanvas;
import com.google.appinventor.client.editor.simple.components.MockCheckBox;
import com.google.appinventor.client.editor.simple.components.MockSwitch;
import com.google.appinventor.client.editor.simple.components.MockCircle;
import com.google.appinventor.client.editor.simple.components.MockCloudDB;
import com.google.appinventor.client.editor.simple.components.MockComponent;
......@@ -391,6 +392,8 @@ public final class SimpleComponentDescriptor {
return new MockCanvas(editor);
} else if (name.equals(MockCheckBox.TYPE)) {
return new MockCheckBox(editor);
} else if (name.equals(MockSwitch.TYPE)) {
return new MockSwitch(editor);
} else if (name.equals(MockImage.TYPE)) {
return new MockImage(editor);
} else if (name.equals(MockLabel.TYPE)) {
......
......@@ -1360,6 +1360,7 @@ Blockly.ComponentBlock.HELPURLS = {
"Button": Blockly.Msg.LANG_COMPONENT_BLOCK_BUTTON_HELPURL,
"Canvas": Blockly.Msg.LANG_COMPONENT_BLOCK_CANVAS_HELPURL,
"CheckBox": Blockly.Msg.LANG_COMPONENT_BLOCK_CHECKBOX_HELPURL,
"Switch": Blockly.Msg.LANG_COMPONENT_BLOCK_SWITCH_HELPURL,
"Clock": Blockly.Msg.LANG_COMPONENT_BLOCK_CLOCK_HELPURL,
"Image": Blockly.Msg.LANG_COMPONENT_BLOCK_IMAGE_HELPURL,
"Label": Blockly.Msg.LANG_COMPONENT_BLOCK_LABEL_HELPURL,
......@@ -1444,6 +1445,7 @@ Blockly.ComponentBlock.PROPERTIES_HELPURLS = {
"Button": Blockly.Msg.LANG_COMPONENT_BLOCK_BUTTON_PROPERTIES_HELPURL,
"Canvas": Blockly.Msg.LANG_COMPONENT_BLOCK_CANVAS_PROPERTIES_HELPURL,
"CheckBox": Blockly.Msg.LANG_COMPONENT_BLOCK_CHECKBOX_PROPERTIES_HELPURL,
"Switch": Blockly.Msg.LANG_COMPONENT_BLOCK_SWITCH_HELPURL,
"Clock": Blockly.Msg.LANG_COMPONENT_BLOCK_CLOCK_PROPERTIES_HELPURL,
"Image": Blockly.Msg.LANG_COMPONENT_BLOCK_IMAGE_PROPERTIES_HELPURL,
"Label": Blockly.Msg.LANG_COMPONENT_BLOCK_LABEL_PROPERTIES_HELPURL,
......@@ -1530,6 +1532,7 @@ Blockly.ComponentBlock.EVENTS_HELPURLS = {
"Canvas": Blockly.Msg.LANG_COMPONENT_BLOCK_CANVAS_EVENTS_HELPURL,
"Clock": Blockly.Msg.LANG_COMPONENT_BLOCK_CLOCK_EVENTS_HELPURL,
"CheckBox": Blockly.Msg.LANG_COMPONENT_BLOCK_CHECKBOX_EVENTS_HELPURL,
"Switch": Blockly.Msg.LANG_COMPONENT_BLOCK_SWITCH_HELPURL,
"Image": Blockly.Msg.LANG_COMPONENT_BLOCK_IMAGE_EVENTS_HELPURL,
"Label": Blockly.Msg.LANG_COMPONENT_BLOCK_LABEL_EVENTS_HELPURL,
"ListPicker": Blockly.Msg.LANG_COMPONENT_BLOCK_LISTPICKER_EVENTS_HELPURL,
......
......@@ -1092,6 +1092,8 @@ Blockly.Msg.en.switch_language_to_english = {
Blockly.Msg.LANG_COMPONENT_BLOCK_LISTPICKER_EVENTS_HELPURL = '/reference/components/userinterface.html#ListPicker';
Blockly.Msg.LANG_COMPONENT_BLOCK_LISTPICKER_METHODS_HELPURL = '/reference/components/userinterface.html#ListPicker';
Blockly.Msg.LANG_COMPONENT_BLOCK_SWITCH_HELPURL = '/reference/components/userinterface.html#Switch';
Blockly.Msg.LANG_COMPONENT_BLOCK_TIMEPICKER_HELPURL = '/reference/components/userinterface.html#TimePicker';
Blockly.Msg.LANG_COMPONENT_BLOCK_DATEPICKER_HELPURL = '/reference/components/userinterface.html#DatePicker';
Blockly.Msg.LANG_COMPONENT_BLOCK_LISTVIEW_HELPURL = '/reference/components/userinterface.html#ListView';
......
......@@ -454,8 +454,10 @@ public class YaVersion {
// - BLOCKS_LANGUAGE_VERSION was incremented to 26
// For YOUNG_ANDROID_VERSION 183:
// - CANVAS_COMPONENT_VERSION was incremented to 11
// For YOUNG_ANDROID_VERESION 184:
// - Added Switch
public static final int YOUNG_ANDROID_VERSION = 183;
public static final int YOUNG_ANDROID_VERSION = 184;
// ............................... Blocks Language Version Number ...............................
......@@ -1051,6 +1053,10 @@ public class YaVersion {
public static final int SPEECHRECOGNIZER_COMPONENT_VERSION = 1;
// For SWITCH_COMPONENT_VERSION 1
// - Initial Version
public static final int SWITCH_COMPONENT_VERSION = 1;
public static final int TABLEARRANGEMENT_COMPONENT_VERSION = 1;
// For TEXTBOX_COMPONENT_VERSION 2:
......
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2018 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import android.app.Activity;
import android.content.res.ColorStateList;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.SwitchCompat;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.PropertyCategory;
import com.google.appinventor.components.annotations.SimpleObject;
import com.google.appinventor.components.annotations.SimpleProperty;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.common.YaVersion;
import com.google.appinventor.components.runtime.util.SdkLevel;
/**
* Toggle switch with the ability to detect initialization, focus
* change (mousing on or off of it), and user clicks.
*
*/
@DesignerComponent(version = YaVersion.SWITCH_COMPONENT_VERSION,
description = "Toggle switch that raises an event when the user clicks on it. " +
"There are many properties affecting its appearance that can be set in " +
"the Designer or Blocks Editor.",
category = ComponentCategory.USERINTERFACE)
@SimpleObject
public final class Switch extends ToggleBase<CompoundButton> {
// Backing for thumb color
private int thumbColorActive;
private int thumbColorInactive;
// Backing for track color
private int trackColorActive;
private int trackColorInactive;
private final Activity activity;
private final SwitchCompat switchView;
/**
* Creates a new Switch component.
*
* @param container container, component will be placed in
*/
public Switch(ComponentContainer container) {
super(container);
this.activity = container.$context();
// Using AppCompat, Switch component is only supported in API 14 and higher
// TODO: If we bump minSDK to 14, then we can change this to only use SwitchCompat.
if (SdkLevel.getLevel() < SdkLevel.LEVEL_ICE_CREAM_SANDWICH) {
switchView = null;
view = new CheckBox(activity);
} else {
switchView = new SwitchCompat(activity);
view = switchView;
}
On(false);
ThumbColorActive(Component.COLOR_WHITE);
ThumbColorInactive(Component.COLOR_LTGRAY);
TrackColorActive(Component.COLOR_GREEN);
TrackColorInactive(Component.COLOR_GRAY);
initToggle();
}
private ColorStateList createSwitchColors(int active_color, int inactive_color) {
return new ColorStateList(new int[][]{
new int[]{android.R.attr.state_checked},
new int[]{}
},
new int[]{
active_color,
inactive_color
});
}
/**
* Returns the switch's thumb color (button that toggles back and forth)
* when the switch is ON/Checked
*
* @return thumb RGB color with alpha
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = false)
public int ThumbColorActive() {
return thumbColorActive;
}
/**
* Specifies the switch's thumb color when switch is ON/Checked
*
* @param argb thumb RGB color with alpha
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR,
defaultValue = Component.DEFAULT_VALUE_COLOR_WHITE)
@SimpleProperty
public void ThumbColorActive(int argb) {
thumbColorActive = argb;
if (switchView != null) {
DrawableCompat.setTintList(switchView.getThumbDrawable(), createSwitchColors(argb, thumbColorInactive));
view.invalidate();
}
}
/**
* Returns the switch's thumb color (button that toggles back and forth)
* when the switch is Off/Unchecked
*
* @return thumb RGB color with alpha
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = true)
public int ThumbColorInactive() {
return thumbColorInactive;
}
/**
* Specifies the switch's thumb color when switch is Off/Unchecked
*
* @param argb thumb RGB color with alpha
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR,
defaultValue = Component.DEFAULT_VALUE_COLOR_LTGRAY)
@SimpleProperty
public void ThumbColorInactive(int argb) {
thumbColorInactive = argb;
if (switchView != null) {
DrawableCompat.setTintList(switchView.getThumbDrawable(), createSwitchColors(thumbColorActive, argb));
view.invalidate();
}
}
/**
* Returns the switch's track color
*
* @return track RGB color with alpha
*/
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = true)
public int TrackColorActive() {
return trackColorActive;
}
@SimpleProperty(category = PropertyCategory.APPEARANCE, userVisible = true)
public int TrackColorInactive() {
return trackColorInactive;
}
/**
* Specifies the switch's track color
*
* @param argb track RGB color with alpha
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR,
defaultValue = Component.DEFAULT_VALUE_COLOR_GREEN)
@SimpleProperty(description = "Color of the toggle track when switched on", userVisible = true)
public void TrackColorActive(int argb) {
trackColorActive = argb;
if (switchView != null) {
DrawableCompat.setTintList(switchView.getTrackDrawable(), createSwitchColors(argb, trackColorInactive));
view.invalidate();
}
}
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_COLOR,
defaultValue = Component.DEFAULT_VALUE_COLOR_DKGRAY)
@SimpleProperty(description = "Color of the toggle track when switched off", userVisible = true)
public void TrackColorInactive(int argb) {
trackColorInactive = argb;
if (switchView != null) {
DrawableCompat.setTintList(switchView.getTrackDrawable(), createSwitchColors(trackColorActive, argb));
view.invalidate();
}
}
/**
* Returns true if the checkbox is checked.
*
* @return {@code true} indicates checked, {@code false} unchecked
*/
@SimpleProperty(
category = PropertyCategory.BEHAVIOR)
public boolean On() {
return view.isChecked();
}
/**
* Checked property setter method.
*
* @param value {@code true} indicates checked, {@code false} unchecked
*/
@DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN,
defaultValue = "False")
@SimpleProperty
public void On(boolean value) {
view.setChecked(value);
view.invalidate();
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2018 Massachusetts Institute of Technology, All rights reserved.
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import org.junit.Before;
import org.junit.Test;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test class for Switch component.
*
* @author srlane@mit.edu (Susan Rati Lane)
*/
public class CheckboxTest extends ToggleTestBase {
private CheckBox aCheckbox;
@Before
public void SetUp() {
super.setUp();
aCheckbox = new CheckBox(getForm());
aToggle = aCheckbox;
}
@Test
public void testCheckboxSharedDefaults() {
testToggleDefaults();
assertFalse(aCheckbox.Checked());
}
@Test
public void testCheckboxSharedProperties() {
testTogglelProperties();
}
@Test
public void testCheckboxEnabled() {
testToggleEnabled();
}
@Test
public void testCheckboxChecked() {
aCheckbox.Checked(false);
assertFalse(aCheckbox.Checked());
aCheckbox.Checked(true);
assertTrue(aCheckbox.Checked());
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2018 Massachusetts Institute of Technology, All rights reserved.
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import org.junit.Before;
import org.junit.Test;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
/**
* Test class for Switch component.
*
* @author srlane@mit.edu (Susan Rati Lane)
*/
public class SwitchTest extends ToggleTestBase {
private Switch aSwitch;
@Before
public void setUp() {
super.setUp();
aSwitch = new Switch(getForm());
aToggle = aSwitch;
}
@Test
public void testSwitchSharedDefaults() {
testToggleDefaults();
}
@Test
public void testSwitchDefaults() {
assertEquals("Invalid default Thumb Color Active", Component.COLOR_WHITE, aSwitch.ThumbColorActive());
assertEquals("Invalid default Thumb Color Inactive", Component.COLOR_LTGRAY, aSwitch.ThumbColorInactive());
assertEquals("Invalid default Track Color Active", Component.COLOR_GREEN, aSwitch.TrackColorActive());
assertEquals("Invalid default Track Color Inactive", Component.COLOR_GRAY, aSwitch.TrackColorInactive());
aSwitch.On(false);
}
@Test
public void testSwitchColors() {
aSwitch.ThumbColorActive(Component.COLOR_MAGENTA);
assertEquals("Invalid Thumb Color Active", Component.COLOR_MAGENTA, aSwitch.ThumbColorActive());
aSwitch.ThumbColorInactive(Component.COLOR_BLACK);
assertEquals("Invalid Thumb Color Inactive", Component.COLOR_BLACK, aSwitch.ThumbColorInactive());
aSwitch.TrackColorActive(Component.COLOR_PINK);
assertEquals("Invalid Track Color Active", Component.COLOR_PINK, aSwitch.TrackColorActive());
aSwitch.TrackColorInactive(Component.COLOR_CYAN);
assertEquals("Invalid Track Color Inactive", Component.COLOR_CYAN, aSwitch.TrackColorInactive());
}
@Test
public void testSwitchOn() {
aSwitch.On(false);
assertFalse(aSwitch.On());
aSwitch.On(true);
assertTrue(aSwitch.On());
}
@Test
public void testSwitchSharedProperties() {
testTogglelProperties();
}
@Test
public void testSwitchEnabled() {
testToggleEnabled();
}
}
// -*- mode: java; c-basic-offset: 2; -*-
// Copyright © 2018 Massachusetts Institute of Technology, All rights reserved.
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0
package com.google.appinventor.components.runtime;
import com.google.appinventor.components.runtime.shadows.org.osmdroid.tileprovider.modules.ShadowMapTileModuleProviderBase;
import com.google.appinventor.components.runtime.shadows.org.osmdroid.views.ShadowMapView;
import org.junit.Before;
import org.junit.Test;
import org.robolectric.annotation.Config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public abstract class ToggleTestBase extends RobolectricTestBase {
ToggleBase aToggle;
@Test
public void testToggleDefaults() {
assertEquals("Expected default background color NONE",Component.COLOR_NONE, aToggle.BackgroundColor());
assertEquals("Expected default Typeface " + Component.TYPEFACE_DEFAULT,Component.TYPEFACE_DEFAULT, aToggle.FontTypeface());
assertTrue(aToggle.Enabled());
assertEquals(Component.FONT_DEFAULT_SIZE, aToggle.FontSize(), 0.0);
assertEquals("Expected default Text Color " + Component.COLOR_DEFAULT, Component.COLOR_DEFAULT, aToggle.TextColor());
}
public void testTogglelProperties() {
aToggle.BackgroundColor(Component.COLOR_ORANGE);
assertEquals("Invalid Switch background color", Component.COLOR_ORANGE, aToggle.BackgroundColor());
aToggle.FontTypeface(Component.TYPEFACE_MONOSPACE);
assertEquals("Invalid Font Typeface", Component.TYPEFACE_MONOSPACE, aToggle.FontTypeface());
aToggle.FontSize(12.0f);
assertEquals(12.0f, aToggle.FontSize(), 0.0f);
aToggle.TextColor(Component.COLOR_RED);
assertEquals("Invalid Text Color", Component.COLOR_RED, aToggle.TextColor());
}
public void testToggleEnabled() {
aToggle.Enabled(false);
assertFalse(aToggle.Enabled());
aToggle.Enabled(true);
assertTrue(aToggle.Enabled());
}
}
......@@ -460,6 +460,7 @@
<li> <a href="#Screen"> Screen </a> </li>
<li> <a href="#Slider"> Slider </a> </li>
<li> <a href="#Spinner"> Spinner </a> </li>
<li> <a href="#Switch"> Switch </a> </li>
<li> <a href="#TextBox"> TextBox </a> </li>
<li> <a href="#TimePicker"> TimePicker </a> </li>
<li> <a href="#WebViewer"> WebViewer </a> </li>
......@@ -1150,6 +1151,47 @@ none
<dt><code>DisplayDropdown()</code></dt>
<dd>displays the dropdown list for selection, same action as when the user clicks on the spinner.</dd>
</dl>
<h2 id="Switch"> Switch </h2>
<p> Switch components can detect user taps and can change
their
boolean state in response. They are identical to Checkboxes except in appearance.</p>
<p> Switches have an on (true) state and an off (false) state. A switch component raises an event when the user taps it to toggle between states. </p>
<h3> Properties </h3>
<dl>
<dt> <code> BackgroundColor </code> </dt>
<dd> Color for switch background. </dd>
<dt> <code> Enabled </code> </dt>
<dd> If set, user can switch to change state and trigger event. </dd>
<dt> <code> Height </code> </dt>
<dd> Switch height (y-size). </dd>
<dt> <code> Width </code> </dt>
<dd> Switch width (x-size). </dd>
<dt> <code> On </code> </dt>
<dd> True if the switch is in the On state, false otherwise. </dd>
<dt> <code> Text </code> </dt>
<dd> Text to display on switch. </dd>
<dt> <code> TextColor </code> </dt>
<dd> Color for switch text. </dd>
<dt> <code> ThumbColorActive </code> </dt>
<dd> Color of the switch button when the switch is in the On state. </dd>
<dt> <code> ThumbColorInactive </code> </dt>
<dd> Color of the switch button when the switch is in the Off state. </dd>
<dt> <code> TrackColorActive </code> </dt>
<dd> Color of the switch slider when the switch is in the On state. </dd>
<dt> <code> TrackColorInactive </code> </dt>
<dd> Color of the switch slider when the switch is in the Off state. </dd>
<dt> <code> Visible </code> </dt>
<dd> If set, switch is visible. </dd>
</dl>
<h3> Events </h3>
<dl>
<dt> <code> Changed() </code> </dt>
<dd> User change the state of the switch from On to Off or back. </dd>
<dt> <code> GotFocus() </code> </dt>
<dd> Check box became the focused component. </dd>
<dt> <code> LostFocus() </code> </dt>
<dd> Check box stopped being the focused component. </dd>
</dl>
<h2 id="TextBox"> TextBox </h2>
<img src="images/textbox.png" alt="" />
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment