-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(android): use material widgets/styles and default to DayNight theme #12353
Conversation
Tests:
|
android/modules/ui/src/java/ti/modules/titanium/ui/android/AndroidModule.java
Outdated
Show resolved
Hide resolved
Feedback (to be continued):
Thats really it. Working very smoothly! Update: All resolved! 🎉 |
Hey @hansemannn. Thanks for giving this a go. Here's my feedback...
This PR defaults the Side Note: I'm thinking about changing the default border style to
Our old buttons have elevation by default too. That's how the button shadow is drawn. But perhaps you're running into the issue below
If your custom theme derives from a material "Bridge" theme, then material widgets such as "MaterialButton" will be rendered wrong (see link below). But if you change your parent theme to a non-bridge theme such as "Theme.MaterialComponents", "Theme.MaterialComponents.Light", "Theme.MaterialComponents.DayNight", etc. then the buttons will be rendered correctly. I know I was telling people to switch over to the material bridge theme in 9.3.0. I'm kind of bummed that the bridge theme has issues with some material widgets like this. But since this PR switches everything over to use material widgets, we don't need the bridge theme for backward compatibility anymore.
You need to override the <!-- Override material button style -->
<style name="TextAppearance.MyTheme.Button" parent="TextAppearance.MaterialComponents.Button">
<item name="android:textAllCaps">false</item>
</style>
<!-- Override old system button style. You should still do this. -->
<style name="Widget.MyTheme.Button" parent="Widget.AppCompat.Button">
<item name="android:textAllCaps">false</item>
</style>
<!-- Apply above to your app/activity theme. -->
<style name="MyTheme" parent="Theme.MaterialComponents">
<item name="textAppearanceButton">@style/TextAppearance.MyTheme.Button</item>
<item name="android:buttonStyle">@style/Widget.MyTheme.Button</item>
<item name="buttonStyle">@style/Widget.MyTheme.Button</item>
</style> Note that I've changed Titanium's default theme to not make button text all caps either as can be seen in our values.xml. You can see proof of this working in our material date picker screenshot here.
I'm aware of the warnings. I haven't addressed this yet. (And yes they're annoying.)
Did this break recently? Do you think it was caused by PR #12449? |
} else { | ||
// await exec(`adb -e shell "run-as ${APP_ID} cat '${filepath}'" > ${dest}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ build/lib/test/test.js line 885 – Missing JSDoc parameter description for 'testResults'. (valid-jsdoc)
} else { | ||
// await exec(`adb -e shell "run-as ${APP_ID} cat '${filepath}'" > ${dest}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ build/lib/test/test.js line 488 – 'stripped' is defined but never used. Allowed unused args must match /^_.+/u. (no-unused-vars)
android/modules/ui/src/java/ti/modules/titanium/ui/widget/TiUIActivityIndicator.java
Outdated
Show resolved
Hide resolved
android/modules/ui/src/java/ti/modules/titanium/ui/android/AndroidModule.java
Show resolved
Hide resolved
It would be nice to have a |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CR: PASS - Unless more additions are added that need reviewing.
TEST CASE
SHOW
const win = Ti.UI.createWindow();
const table = Ti.UI.createTableView();
function section_dayNight() {
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection();
const view = Ti.UI.createView({
layout: 'horizontal',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE
});
const center = Ti.UI.createView({
height: 60
});
const label = Ti.UI.createLabel({
text: 'Toggle dark theme: '
});
const toggle = Ti.UI.createSwitch({
value: false
});
toggle.addEventListener('change', e => {
if (Ti.UI.overrideUserInterfaceStyle != Ti.UI.USER_INTERFACE_STYLE_DARK) {
Ti.UI.overrideUserInterfaceStyle = Ti.UI.USER_INTERFACE_STYLE_DARK;
} else {
Ti.UI.overrideUserInterfaceStyle = Ti.UI.USER_INTERFACE_STYLE_UNSPECIFIED;
}
});
view.add([label, toggle]);
center.add(view);
row.add(center);
section.add(row);
return section;
}
function section_buttons() {
const title = Ti.UI.createLabel({
text: 'Button',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
view.add([
Ti.UI.createButton({
top: 10,
title: 'BUTTON_STYLE_OPTION_POSITIVE',
style: Ti.UI.BUTTON_STYLE_OPTION_POSITIVE
}),
Ti.UI.createButton({
top: 5,
title: 'BUTTON_STYLE_OPTION_NEGATIVE',
style: Ti.UI.BUTTON_STYLE_OPTION_NEGATIVE
}),
Ti.UI.createButton({
top: 5,
title: 'BUTTON_STYLE_OPTION_NEUTRAL',
style: Ti.UI.BUTTON_STYLE_OPTION_NEUTRAL
}),
Ti.UI.createButton({
top: 5,
title: 'BUTTON_STYLE_OUTLINED',
style: Ti.UI.BUTTON_STYLE_OUTLINED
}),
Ti.UI.createButton({
top: 5,
title: 'BUTTON_STYLE_TEXT',
style: Ti.UI.BUTTON_STYLE_TEXT
}),
Ti.UI.createButton({
top: 5,
title: 'BUTTON_STYLE_FILLED',
style: Ti.UI.BUTTON_STYLE_FILLED
})
]);
row.add(view);
section.add(row);
return section;
}
function section_textFields() {
const title = Ti.UI.createLabel({
text: 'TextField',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
view.add([
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_FILLED',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_FILLED
}),
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_BEZEL',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_BEZEL
}),
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_LINE',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_LINE
}),
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_ROUNDED',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_ROUNDED
}),
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_NONE',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_NONE
}),
Ti.UI.createTextField({
top: 10,
left: 10,
right: 10,
hintText: 'INPUT_BORDERSTYLE_UNDERLINED',
borderStyle: Ti.UI.INPUT_BORDERSTYLE_UNDERLINED
})
]);
row.add(view);
section.add(row);
return section;
}
function section_switch() {
const title = Ti.UI.createLabel({
text: 'Switch',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
view.add([
Ti.UI.createSwitch({
style: Ti.UI.SWITCH_STYLE_CHECKBOX,
title: 'SWITCH_STYLE_CHECKBOX',
top: 10
}),
Ti.UI.createSwitch({
style: Ti.UI.SWITCH_STYLE_SLIDER,
title: 'SWITCH_STYLE_SLIDER',
top: 10
}),
Ti.UI.createSwitch({
style: Ti.UI.SWITCH_STYLE_TOGGLE_BUTTON,
title: 'SWITCH_STYLE_TOGGLE_BUTTON',
top: 10
}),
Ti.UI.createSwitch({
style: Ti.UI.SWITCH_STYLE_CHIP,
title: 'SWITCH_STYLE_CHIP',
top: 10
})
]);
row.add(view);
section.add(row);
return section;
}
function section_alert() {
const title = Ti.UI.createLabel({
text: 'Dialog',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
const button_alert = Ti.UI.createButton({
top: 10,
title: 'alert()'
});
const button_alertDialog = Ti.UI.createButton({
top: 10,
title: 'Ti.UI.AlertDialog'
});
const button_optionDialog = Ti.UI.createButton({
top: 10,
title: 'Ti.UI.OptionDialog'
});
button_alert.addEventListener('click', e => {
alert('This is an alert.');
});
button_alertDialog.addEventListener('click', e => {
Ti.UI.createAlertDialog({
cancel: 1,
buttonNames: ['Okay', 'Cancel'],
message: 'This is an Ti.UI.AlertDialog.',
title: 'Ti.UI.AlertDialog'
}).show();
});
button_optionDialog.addEventListener('click', e => {
Ti.UI.createOptionDialog({
cancel: 1,
options: ['Okay', 'Cancel'],
selectedIndex: 0,
destructive: 1,
title: 'Ti.UI.OptionDialog'
}).show();
});
view.add([
button_alert,
button_alertDialog,
button_optionDialog
]);
row.add(view);
section.add(row);
return section;
}
function section_cardView() {
const title = Ti.UI.createLabel({
text: 'CardView',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
if (Ti.Platform.osname === 'android') {
const card = Ti.UI.Android.createCardView({
layout: 'vertical',
padding: 16,
top: 10,
left: 10,
right: 10,
});
card.add(Ti.UI.createLabel({
text: 'This is a Ti.UI.Android.CardView',
maxLines: 1,
width: Ti.UI.FILL
}));
view.add([card]);
}
row.add(view);
section.add(row);
return section;
}
function section_activityIndicator() {
const title = Ti.UI.createLabel({
text: 'ActivityIndicator',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
function createIndicator(message, style) {
const indicator = Ti.UI.createActivityIndicator({
message: message,
style: style,
top: 10
});
indicator.show();
return indicator;
}
view.add([
createIndicator('PLAIN', Ti.UI.ActivityIndicatorStyle.PLAIN),
createIndicator('BIG', Ti.UI.ActivityIndicatorStyle.BIG),
createIndicator('DARK', Ti.UI.ActivityIndicatorStyle.DARK),
createIndicator('BIG_DARK', Ti.UI.ActivityIndicatorStyle.BIG_DARK),
]);
row.add(view);
section.add(row);
return section;
}
function section_progressBar() {
const title = Ti.UI.createLabel({
text: 'ProgressBar',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
const progressBar = Ti.UI.createProgressBar({
top: 10,
min: 0,
max: 100,
width: '80%',
animated: false
});
const progressBar_animated = Ti.UI.createProgressBar({
top: 10,
min: 0,
max: 100,
width: '80%'
});
setInterval(_ => {
if (progressBar.value < progressBar.max) {
progressBar.value++;
progressBar.message = `${progressBar.value}%`;
} else {
progressBar.value = 0;
}
if (progressBar_animated.value < progressBar_animated.max) {
progressBar_animated.value++;
progressBar_animated.message = `${progressBar_animated.value}% (animated: true)`;
} else {
progressBar_animated.value = 0;
}
}, 50);
view.add([
progressBar,
progressBar_animated
]);
row.add(view);
section.add(row);
return section;
}
function section_picker() {
const title = Ti.UI.createLabel({
text: 'Picker',
left: 10,
font: {
fontSize: 26
}
});
const row = Ti.UI.createTableViewRow();
const section = Ti.UI.createTableViewSection({
headerView: title
});
const view = Ti.UI.createView({
layout: 'vertical',
width: Ti.UI.SIZE,
height: Ti.UI.SIZE,
bottom: 10
});
const button_date = Ti.UI.createButton({
top: 10,
title: 'Date'
});
const button_time = Ti.UI.createButton({
top: 10,
title: 'Time'
});
button_date.addEventListener('click', e => {
const picker = Ti.UI.createPicker({
type: Ti.UI.PICKER_TYPE_DATE,
minDate: new Date(2020, 8, 10),
maxDate: new Date(2021, 1, 24),
value: new Date(2021, 0, 1)
});
picker.showDatePickerDialog({
title: 'Date Picker'
});
});
button_time.addEventListener('click', e => {
const picker = Ti.UI.createPicker({
type: Ti.UI.PICKER_TYPE_TIME,
value: new Date(2021, 0, 1, 12)
});
picker.showTimePickerDialog({
title: 'Time Picker'
});
});
view.add([
button_date,
button_time
]);
row.add(view);
section.add(row);
return section;
}
table.data = [
section_dayNight(),
section_buttons(),
section_textFields(),
section_alert(),
section_cardView(),
section_switch(),
section_activityIndicator(),
section_progressBar(),
section_picker()
];
win.add(table);
win.open();
@jquick-axway The following two bugs (only tracked internally until now) are remaining:
|
@hansemannn, regarding your Regarding your |
Fixes TIMOB-28351
Fixes TIMOB-28353
Fixes TIMOB-28367
Fixes TIMOB-28369
Fixes TIMOB-28370
To be able to merge this without squashing it down to one commit, I had to locally rebase and force push. Local testing indicates it passes all tests still - but I wanted to retain the tracking of this PR and the separate commits (hence why I didn't manually merge or open separate PR). |
// Update indicator to use a big or small style. | ||
int[] idArray = new int[] { | ||
R.attr.trackThickness, | ||
R.attr.indicatorSize, | ||
R.attr.indicatorInset | ||
}; | ||
int themeId = R.style.Widget_MaterialComponents_CircularProgressIndicator_ExtraSmall; | ||
if ((styleId == BIG) || (styleId == BIG_DARK)) { | ||
themeId = R.style.Widget_MaterialComponents_CircularProgressIndicator_Medium; | ||
} | ||
ContextThemeWrapper context = new ContextThemeWrapper(this.progress.getContext(), themeId); | ||
TypedArray typedArray = context.obtainStyledAttributes(null, idArray, 0, 0); | ||
int value = typedArray.getDimensionPixelSize(0, this.progress.getTrackThickness()); | ||
this.progress.setTrackThickness(typedArray.getDimensionPixelSize(0, this.progress.getTrackThickness())); | ||
this.progress.setIndicatorSize(typedArray.getDimensionPixelSize(1, this.progress.getIndicatorSize())); | ||
this.progress.setIndicatorInset(typedArray.getDimensionPixelSize(2, this.progress.getIndicatorInset())); | ||
typedArray.recycle(); | ||
|
||
// Update indicator's color. | ||
if (this.proxy.hasPropertyAndNotNull(TiC.PROPERTY_INDICATOR_COLOR)) { | ||
int color = TiConvert.toColor(TiConvert.toString(this.proxy.getProperty(TiC.PROPERTY_INDICATOR_COLOR))); | ||
this.progress.getIndeterminateDrawable().setColorFilter( | ||
new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN)); | ||
} else if ((styleId == DARK) || (styleId == BIG_DARK)) { | ||
this.progress.getIndeterminateDrawable().setColorFilter( | ||
new PorterDuffColorFilter(Color.DKGRAY, PorterDuff.Mode.SRC_IN)); | ||
} else { | ||
this.progress.getIndeterminateDrawable().clearColorFilter(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jquick-axway This is causing sizing issues in the current master/10_0_X branch. We used to do:
Ti.UI.createActivityIndicator(Object.assign({
width: 80,
height: 80,
style: Ti.UI.ActivityIndicatorStyle.BIG,
indicatorColor: 'textColor'
}, opts));
which used to resize the indicator properly but doesn't anymore
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The activity indicator was never resizable. Not in the old Android version. Nor on iOS. So, setting the width/height properties doesn't buy you anything.
That said, the "material" version of Ti.UI.ActivityIndicatorStyle.BIG
is smaller than the old "holo" version. The R.style.Widget_MaterialComponents_CircularProgressIndicator_Medium
style is the biggest version available to us.
My advise is to get rid of the "width" and "height" properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, I take it back. The old Android activity indicator supports scaling "down", but not scaling "up".
(iOS' activity indicator does not support scaling up or down at all.)
I can look into this, but I don't think the material version of this widget supports this at all without some customization. My advice is to stick to the native size and remove the width/height still.
JIRA: