Skip to content

Commit

Permalink
feat(android): add Ti.UI.ButtonBar (#12389)
Browse files Browse the repository at this point in the history
Fixes TIMOB-25954
  • Loading branch information
jquick-axway authored and sgtcoolguy committed Feb 26, 2021
1 parent a4e61bf commit 5a6be04
Show file tree
Hide file tree
Showing 6 changed files with 408 additions and 29 deletions.
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<style name="Widget.Titanium.OutlinedButton.IconOnly" parent="Widget.MaterialComponents.Button.OutlinedButton">
<item name="iconGravity">textStart</item>
<item name="iconPadding">0dp</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:paddingLeft">12dp</item>
<item name="android:paddingRight">12dp</item>
<item name="android:minWidth">48dp</item>
<item name="android:minHeight">48dp</item>
</style>
</resources>
@@ -0,0 +1,32 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2021 by Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
package ti.modules.titanium.ui;

import android.app.Activity;
import org.appcelerator.kroll.annotations.Kroll;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.view.TiUIView;
import ti.modules.titanium.ui.widget.TiUIButtonBar;

@Kroll.proxy(creatableInModule = UIModule.class, propertyAccessors = {
TiC.PROPERTY_LABELS,
})
public class ButtonBarProxy extends TiViewProxy
{
@Override
public TiUIView createView(Activity activity)
{
return new TiUIButtonBar(this);
}

@Override
public String getApiName()
{
return "Ti.UI.ButtonBar";
}
}
@@ -0,0 +1,199 @@
/**
* Appcelerator Titanium Mobile
* Copyright (c) 2021 by Axway, Inc. All Rights Reserved.
* Licensed under the terms of the Apache Public License
* Please see the LICENSE included with this distribution for details.
*/
package ti.modules.titanium.ui.widget;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.appcompat.view.ContextThemeWrapper;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.button.MaterialButtonToggleGroup;
import java.util.HashMap;
import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.titanium.R;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.proxy.TiViewProxy;
import org.appcelerator.titanium.util.TiConvert;
import org.appcelerator.titanium.util.TiUIHelper;
import org.appcelerator.titanium.view.TiUIView;

public class TiUIButtonBar extends TiUIView
{
private static final String TAG = "TiUIButtonBar";

public TiUIButtonBar(TiViewProxy proxy)
{
super(proxy);

// Create view group used to host buttons.
MaterialButtonToggleGroup buttonGroup = new MaterialButtonToggleGroup(proxy.getActivity());
buttonGroup.setSelectionRequired(false);
buttonGroup.setSingleSelection(false);
buttonGroup.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(
View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom)
{
TiUIHelper.firePostLayoutEvent(getProxy());
}
});
setNativeView(buttonGroup);
}

@Override
public void processProperties(KrollDict properties)
{
// Validate.
if (properties == null) {
return;
}

// Apply given properties to view.
if (properties.containsKey(TiC.PROPERTY_LABELS)) {
processLabels(properties.get(TiC.PROPERTY_LABELS));
}

// Let base class handle all other view property settings.
super.processProperties(properties);
}

@Override
public void propertyChanged(String key, Object oldValue, Object newValue, KrollProxy proxy)
{
// Validate.
if (key == null) {
return;
}

// Handle property change.
if (key.equals(TiC.PROPERTY_LABELS)) {
processLabels(newValue);
} else {
super.propertyChanged(key, oldValue, newValue, proxy);
}
}

private void processLabels(Object labels)
{
// Do not continue if proxy has been released.
if (this.proxy == null) {
return;
}

// Fetch the button group view.
MaterialButtonToggleGroup buttonGroup = getButtonGroup();
if (buttonGroup == null) {
return;
}

// Clear the previously assigned buttons.
buttonGroup.removeAllViews();

// Fetch "labels" property and validate it.
if ((labels == null) || !labels.getClass().isArray()) {
return;
}
Object[] objectArray = (Object[]) labels;
if (objectArray.length <= 0) {
return;
}

// Process the labels object.
if (objectArray[0] instanceof String) {
// We were given an array of button titles.
for (Object title : objectArray) {
addButton(TiConvert.toString(title, ""), null, null, true);
}
} else if (objectArray[0] instanceof HashMap) {
// We were given an array of Titanium "BarItemType" dictionaries.
for (Object nextObject : objectArray) {
// Make sure next element is a dictionary.
if ((nextObject instanceof HashMap) == false) {
continue;
}
HashMap hashMap = (HashMap) nextObject;

// Fetch the optional "title" property.
String title = TiConvert.toString(hashMap.get(TiC.PROPERTY_TITLE), "");

// Fetch the optional "accessibilityLabel" property.
String accessibilityLabel = TiConvert.toString(hashMap.get(TiC.PROPERTY_ACCESSIBILITY_LABEL), null);

// Fetch the optional "image" property and load it as a drawable.
Drawable imageDrawable = null;
Object imageObject = hashMap.get(TiC.PROPERTY_IMAGE);
if (imageObject != null) {
imageDrawable = TiUIHelper.getResourceDrawable(imageObject);
}

// Fetch the optional "enabled" flag.
boolean isEnabled = TiConvert.toBoolean(hashMap.get(TiC.PROPERTY_ENABLED), true);

// Add the button.
addButton(title, accessibilityLabel, imageDrawable, isEnabled);
}
}
}

private void addButton(String title, String accessibilityLabel, Drawable imageDrawable, boolean isEnabled)
{
// Fetch the button group view.
MaterialButtonToggleGroup buttonGroup = getButtonGroup();
if (buttonGroup == null) {
return;
}

// Title must be non-null.
if (title == null) {
title = "";
}

// Create a button with given settings and add it to view group.
Context context = buttonGroup.getContext();
int attributeId = R.attr.materialButtonOutlinedStyle;
if (title.isEmpty() && (imageDrawable != null)) {
context = new ContextThemeWrapper(context, R.style.Widget_Titanium_OutlinedButton_IconOnly);
attributeId = R.attr.materialButtonToggleGroupStyle;
}
MaterialButton button = new MaterialButton(context, null, attributeId);
button.setText(title);
if ((accessibilityLabel != null) && !accessibilityLabel.isEmpty()) {
button.setContentDescription(accessibilityLabel);
}
if (imageDrawable != null) {
button.setIcon(imageDrawable);
}
buttonGroup.addView(button);
button.setCheckable(false);
button.setEnabled(isEnabled);
button.setOnClickListener((view) -> {
if (this.proxy == null) {
return;
}
for (int index = 0; index < buttonGroup.getChildCount(); index++) {
View childView = buttonGroup.getChildAt(index);
if (childView == view) {
KrollDict data = new KrollDict();
data.put(TiC.PROPERTY_INDEX, index);
this.proxy.fireEvent(TiC.EVENT_CLICK, data);
return;
}
}
});
}

private MaterialButtonToggleGroup getButtonGroup()
{
View view = getNativeView();
if (view instanceof MaterialButtonToggleGroup) {
return (MaterialButtonToggleGroup) view;
}
return null;
}
}
45 changes: 16 additions & 29 deletions apidoc/Titanium/UI/ButtonBar.yml
Expand Up @@ -2,30 +2,18 @@
name: Titanium.UI.ButtonBar
summary: An iOS button bar component.
description: |
The button bar is a set of buttons joined into a single control. Each button in a
button bar can have a text label or an icon, but not both.
The button bar is a set of buttons joined into a single control.
On iOS, you can set up the buttons with either a title or image, but not both.
On Android, you can set up the buttons with a title, image, or both.
Use the <Titanium.UI.createButtonBar> method or **`<ButtonBar>`** Alloy element to create a button bar.
The [TabbedBar](Titanium.UI.iOS.TabbedBar) control is a button bar where the
last selected button mantains a pressed or selected state. The following discussion
applies to both button bar and tabbed bar.
The buttons share a common style, defined by the `style` property. This can be
set to one of the constants defined in
[Titanium.UI.iOS.SystemButtonStyle](Titanium.UI.iOS.SystemButtonStyle):
* `PLAIN`. Default style for `ButtonBar` and `TabbedBar`.
* `BORDERED`. Creates a bar like the `PLAIN` bar, but with a heavier border.
Note that you cannot style individual buttons in a button bar. If you want to give a
distinct visual style to individual buttons, to use an icon and text on the same button,
or to use a button-bar type component on a platform other than iOS, you can use a set
of individual [Button](Titanium.UI.Button) controls wrapped in a
[View](Titanium.UI.View) to create the appearance of a button bar.
extends: Titanium.UI.View
since: "0.8"
platforms: [iphone, ipad, macos]
since: {android: "10.0.0", iphone: "0.8", ipad: "0.8", macos: "9.2.0"}
platforms: [android, iphone, ipad, macos]
excludes:
events: [ 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'dblclick',
'doubletap', 'longclick', 'singletap', 'swipe', 'twofingertap' ]
Expand All @@ -37,7 +25,7 @@ events:
summary: Fired when a button is clicked.
properties:
- name: index
summary: Index of the clicked button.
summary: Index of the clicked button.
type: Number
properties:
- name: index
Expand All @@ -60,7 +48,7 @@ properties:
``` xml
<Alloy>
<ButtonBar platform="ios">
<ButtonBar>
<Labels>
<!-- Specify text with node text or "title" attribute. -->
<Label>button 1</Label>
Expand Down Expand Up @@ -106,15 +94,15 @@ examples:
- title: Simple 3 button button bar
example: |
``` js
var bb1 = Titanium.UI.createButtonBar({
labels:['One', 'Two', 'Three'],
backgroundColor:'#336699',
top:50,
style:Titanium.UI.iOS.SystemButtonStyle.PLAIN,
height:25,
width:200
const win = Ti.UI.createWindow();
const buttonBar = Titanium.UI.createButtonBar({
labels:['One', 'Two', 'Three']
});
buttonBar.addEventListener('click', (e) => {
console.log(`Clicked on button index: ${e.index}`);
});
win.add(bb1);
win.add(buttonBar);
win.open();
```
- title: Alloy XML Markup
Expand All @@ -124,7 +112,7 @@ examples:
``` xml
<Alloy>
<Window id="win">
<ButtonBar id="bb1" platform="ios" backgroundColor="#369" top="50" height="25" width="200">
<ButtonBar id="buttonBar">
<!-- The Labels tag sets the ButtonBar.labels property -->
<Labels>
<!-- Specify text with node text or the title attribute. -->
Expand All @@ -133,7 +121,6 @@ examples:
<Label>Two</Label>
<Label>Three</Label>
</Labels>
<!-- Place additional views for the ButtonBar here. -->
</ButtonBar>
</Window>
</Alloy>
Expand Down
1 change: 1 addition & 0 deletions tests/Resources/app.js
Expand Up @@ -151,6 +151,7 @@ function loadTests() {
}
require('./ti.ui.attributedstring.test');
require('./ti.ui.button.test');
require('./ti.ui.buttonbar.test');
require('./ti.ui.clipboard.test');
require('./ti.ui.constants.test');
require('./ti.ui.emaildialog.test');
Expand Down

0 comments on commit 5a6be04

Please sign in to comment.