Skip to content

Commit 3638cce

Browse files
committed
feat: ios basic shape support
1 parent 72765f9 commit 3638cce

File tree

6 files changed

+323
-38
lines changed

6 files changed

+323
-38
lines changed

src/button/button.ios.ts

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dynamicElevationOffsetProperty, elevationProperty, getRippleColor, rippleColorProperty, themer } from '@nativescript-community/ui-material-core';
1+
import { dynamicElevationOffsetProperty, elevationProperty, getRippleColor, rippleColorProperty, shapeProperty, themer } from '@nativescript-community/ui-material-core';
22
import {
33
Background,
44
Color,
@@ -123,6 +123,60 @@ export class Button extends ButtonBase {
123123
this.setTopRightCornerRadius(value);
124124
this.applyShapeScheme();
125125
}
126+
shapeScheme: MDCShapeScheme;
127+
private getShapeScheme() {
128+
if (!this.shapeScheme) {
129+
if (this.shape) {
130+
// we need to copy it as if we change border radius on this view
131+
// it will change for everyone else
132+
this.shapeScheme = MDCShapeScheme.new();
133+
const shapeScheme = themer.getShape(this.shape);
134+
this.shapeScheme.smallComponentShape = shapeScheme.smallComponentShape.copy();
135+
} else {
136+
this.shapeScheme = MDCShapeScheme.new();
137+
const shapeCategory = MDCShapeCategory.new();
138+
this.shapeScheme.smallComponentShape = shapeCategory;
139+
}
140+
}
141+
return this.shapeScheme;
142+
}
143+
144+
private setBottomLeftCornerRadius(value: number) {
145+
const shapeScheme = this.getShapeScheme();
146+
const current = shapeScheme.smallComponentShape.bottomLeftCorner;
147+
if (current instanceof MDCCutCornerTreatment) {
148+
shapeScheme.smallComponentShape.bottomLeftCorner = MDCCornerTreatment.cornerWithCut(value);
149+
} else {
150+
shapeScheme.smallComponentShape.bottomLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
151+
}
152+
}
153+
private setBottomRightCornerRadius(value: number) {
154+
const shapeScheme = this.getShapeScheme();
155+
const current = shapeScheme.smallComponentShape.bottomRightCorner;
156+
if (current instanceof MDCCutCornerTreatment) {
157+
shapeScheme.smallComponentShape.bottomRightCorner = MDCCornerTreatment.cornerWithCut(value);
158+
} else {
159+
shapeScheme.smallComponentShape.bottomRightCorner = MDCCornerTreatment.cornerWithRadius(value);
160+
}
161+
}
162+
private setTopLeftCornerRadius(value: number) {
163+
const shapeScheme = this.getShapeScheme();
164+
const current = shapeScheme.smallComponentShape.topLeftCorner;
165+
if (current instanceof MDCCutCornerTreatment) {
166+
shapeScheme.smallComponentShape.topLeftCorner = MDCCornerTreatment.cornerWithCut(value);
167+
} else {
168+
shapeScheme.smallComponentShape.topLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
169+
}
170+
}
171+
private setTopRightCornerRadius(value: number) {
172+
const shapeScheme = this.getShapeScheme();
173+
const current = shapeScheme.smallComponentShape.topRightCorner;
174+
if (current instanceof MDCCutCornerTreatment) {
175+
shapeScheme.smallComponentShape.topRightCorner = MDCCornerTreatment.cornerWithCut(value);
176+
} else {
177+
shapeScheme.smallComponentShape.topRightCorner = MDCCornerTreatment.cornerWithRadius(value);
178+
}
179+
}
126180

127181
public createNativeView() {
128182
const view = MDCButton.new();
@@ -210,32 +264,6 @@ export class Button extends ButtonBase {
210264
}
211265
}
212266

213-
shapeScheme: MDCShapeScheme;
214-
private getShapeScheme() {
215-
if (!this.shapeScheme) {
216-
this.shapeScheme = MDCShapeScheme.new();
217-
const shapeCategory = MDCShapeCategory.new();
218-
this.shapeScheme.smallComponentShape = shapeCategory;
219-
}
220-
return this.shapeScheme;
221-
}
222-
223-
private setBottomLeftCornerRadius(value: number) {
224-
const shapeScheme = this.getShapeScheme();
225-
shapeScheme.smallComponentShape.bottomLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
226-
}
227-
private setBottomRightCornerRadius(value: number) {
228-
const shapeScheme = this.getShapeScheme();
229-
shapeScheme.smallComponentShape.bottomRightCorner = MDCCornerTreatment.cornerWithRadius(value);
230-
}
231-
private setTopLeftCornerRadius(value: number) {
232-
const shapeScheme = this.getShapeScheme();
233-
shapeScheme.smallComponentShape.topLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
234-
}
235-
private setTopRightCornerRadius(value: number) {
236-
const shapeScheme = this.getShapeScheme();
237-
shapeScheme.smallComponentShape.topRightCorner = MDCCornerTreatment.cornerWithRadius(value);
238-
}
239267
_setNativeClipToBounds() {
240268
// const backgroundInternal = this.style.backgroundInternal;
241269
// this.nativeViewProtected.clipsToBounds =
@@ -266,4 +294,10 @@ export class Button extends ButtonBase {
266294
super[colorProperty.setNative](value);
267295
this.nativeViewProtected.setImageTintColorForState(color, UIControlState.Normal);
268296
}
297+
[shapeProperty.setNative](shape: string) {
298+
// TODO: for now we cant change after set
299+
// this.shapeScheme = null;
300+
this.getShapeScheme();
301+
this.applyShapeScheme();
302+
}
269303
}

src/cardview/cardview.ios.ts

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
import { dynamicElevationOffsetProperty, elevationProperty, getRippleColor, rippleColorProperty, themer } from '@nativescript-community/ui-material-core';
2-
import { Background, Color, Screen, backgroundInternalProperty, isUserInteractionEnabledProperty } from '@nativescript/core';
2+
import {
3+
Background,
4+
Color,
5+
Screen,
6+
backgroundInternalProperty,
7+
borderBottomLeftRadiusProperty,
8+
borderBottomRightRadiusProperty,
9+
borderTopLeftRadiusProperty,
10+
borderTopRightRadiusProperty,
11+
isUserInteractionEnabledProperty
12+
} from '@nativescript/core';
313
import { CardViewBase } from './cardview-common';
414

515
// use custom class to get the same behavior as android which is
@@ -21,13 +31,18 @@ class Card extends MDCCardCollectionCell {
2131

2232
export class CardView extends CardViewBase {
2333
nativeViewProtected: Card;
24-
34+
scheme: MDCContainerScheme;
2535
public createNativeView() {
2636
const view = Card.new() as Card;
2737
const colorScheme = themer.getAppColorScheme() as MDCSemanticColorScheme;
2838
if (colorScheme) {
2939
const scheme = MDCContainerScheme.alloc().init();
3040
scheme.colorScheme = colorScheme;
41+
this.scheme = scheme;
42+
if (this.shape) {
43+
this.scheme.shapeScheme = this.getShapeScheme();
44+
}
45+
console.log('createNativeView', this.scheme.shapeScheme);
3146
view.applyThemeWithScheme(scheme);
3247
}
3348
view.interactable = this.isUserInteractionEnabled;
@@ -44,7 +59,83 @@ export class CardView extends CardViewBase {
4459
getDefaultDynamicElevationOffset() {
4560
return 1;
4661
}
62+
applyShapeScheme() {
63+
if (this.scheme) {
64+
this.scheme.shapeScheme = this.shapeScheme;
65+
console.log('applyShapeScheme');
66+
this.nativeViewProtected.applyThemeWithScheme(this.scheme);
67+
}
68+
}
69+
[borderBottomLeftRadiusProperty.setNative](value) {
70+
this.setBottomLeftCornerRadius(value);
71+
this.applyShapeScheme();
72+
}
73+
[borderBottomRightRadiusProperty.setNative](value) {
74+
this.setBottomRightCornerRadius(value);
75+
this.applyShapeScheme();
76+
}
77+
[borderTopLeftRadiusProperty.setNative](value) {
78+
this.setTopLeftCornerRadius(value);
79+
this.applyShapeScheme();
80+
}
81+
[borderTopRightRadiusProperty.setNative](value) {
82+
this.setTopRightCornerRadius(value);
83+
this.applyShapeScheme();
84+
}
85+
shapeScheme: MDCShapeScheme;
86+
private getShapeScheme() {
87+
if (!this.shapeScheme) {
88+
if (this.shape) {
89+
// we need to copy it as if we change border radius on this view
90+
// it will change for everyone else
91+
this.shapeScheme = MDCShapeScheme.new();
92+
const shapeScheme = themer.getShape(this.shape);
93+
this.shapeScheme.smallComponentShape = shapeScheme.smallComponentShape.copy();
94+
} else {
95+
this.shapeScheme = MDCShapeScheme.new();
96+
const shapeCategory = MDCShapeCategory.new();
97+
this.shapeScheme.smallComponentShape = shapeCategory;
98+
}
99+
}
100+
return this.shapeScheme;
101+
}
47102

103+
private setBottomLeftCornerRadius(value: number) {
104+
const shapeScheme = this.getShapeScheme();
105+
const current = shapeScheme.smallComponentShape.bottomLeftCorner;
106+
if (current instanceof MDCCutCornerTreatment) {
107+
shapeScheme.smallComponentShape.bottomLeftCorner = MDCCornerTreatment.cornerWithCut(value);
108+
} else {
109+
shapeScheme.smallComponentShape.bottomLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
110+
}
111+
}
112+
private setBottomRightCornerRadius(value: number) {
113+
const shapeScheme = this.getShapeScheme();
114+
const current = shapeScheme.smallComponentShape.bottomRightCorner;
115+
if (current instanceof MDCCutCornerTreatment) {
116+
shapeScheme.smallComponentShape.bottomRightCorner = MDCCornerTreatment.cornerWithCut(value);
117+
} else {
118+
shapeScheme.smallComponentShape.bottomRightCorner = MDCCornerTreatment.cornerWithRadius(value);
119+
}
120+
}
121+
private setTopLeftCornerRadius(value: number) {
122+
const shapeScheme = this.getShapeScheme();
123+
const current = shapeScheme.smallComponentShape.topLeftCorner;
124+
if (current instanceof MDCCutCornerTreatment) {
125+
shapeScheme.smallComponentShape.topLeftCorner = MDCCornerTreatment.cornerWithCut(value);
126+
} else {
127+
shapeScheme.smallComponentShape.topLeftCorner = MDCCornerTreatment.cornerWithRadius(value);
128+
}
129+
}
130+
private setTopRightCornerRadius(value: number) {
131+
const shapeScheme = this.getShapeScheme();
132+
const current = shapeScheme.smallComponentShape.topRightCorner;
133+
if (current instanceof MDCCutCornerTreatment) {
134+
shapeScheme.smallComponentShape.topRightCorner = MDCCornerTreatment.cornerWithCut(value);
135+
} else {
136+
shapeScheme.smallComponentShape.topRightCorner = MDCCornerTreatment.cornerWithRadius(value);
137+
}
138+
}
48139
// trick to get the same behavior as android (don't disable all children)
49140
[isUserInteractionEnabledProperty.setNative](value: boolean) {
50141
this.nativeViewProtected.interactable = value;
@@ -71,9 +162,9 @@ export class CardView extends CardViewBase {
71162
if (value.color) {
72163
this.nativeViewProtected.backgroundColor = value.color ? value.color.ios : null;
73164
}
74-
this.nativeViewProtected.setBorderWidthForState(value.borderLeftWidth / scale, MDCCardCellState.Normal);
75-
this.nativeViewProtected.setBorderColorForState(value.borderTopColor ? value.borderTopColor.ios : null, MDCCardCellState.Normal);
76-
this.nativeViewProtected.cornerRadius = value.borderTopLeftRadius / scale;
165+
// this.nativeViewProtected.setBorderWidthForState(value.borderLeftWidth / scale, MDCCardCellState.Normal);
166+
// this.nativeViewProtected.setBorderColorForState(value.borderTopColor ? value.borderTopColor.ios : null, MDCCardCellState.Normal);
167+
// this.nativeViewProtected.cornerRadius = value.borderTopLeftRadius / scale;
77168
}
78169
}
79170
[rippleColorProperty.setNative](color: Color) {

src/core/index.ios.ts

Lines changed: 77 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,48 @@
1-
import { Background, Button, Color, ControlStateChangeListener, GestureTypes, TouchAction, TouchGestureEventData, Utils, View, backgroundInternalProperty } from '@nativescript/core';
2-
import { TypographyOptions } from '.';
3-
import { applyMixins } from './index.common';
1+
import {
2+
Background,
3+
Button,
4+
Color,
5+
ControlStateChangeListener,
6+
GestureTypes,
7+
LengthPercentUnit,
8+
TouchAction,
9+
TouchGestureEventData,
10+
Utils,
11+
View,
12+
backgroundInternalProperty
13+
} from '@nativescript/core';
14+
import { ShapeProperties, TypographyOptions } from '.';
15+
import { CornerFamily, applyMixins } from './index.common';
416
import { cssProperty, dynamicElevationOffsetProperty, elevationProperty, rippleColorProperty } from './cssproperties';
517
export * from './cssproperties';
618
export { applyMixins };
719

20+
function createCornerFamily(cornerFamily: CornerFamily): MDCShapeCornerFamily {
21+
switch (cornerFamily) {
22+
case CornerFamily.CUT:
23+
return MDCShapeCornerFamily.Cut;
24+
default:
25+
case CornerFamily.ROUNDED:
26+
return MDCShapeCornerFamily.Rounded;
27+
}
28+
}
29+
function cornerTreatment(cornerFamily: CornerFamily, cornerSize: number | LengthPercentUnit) {
30+
let corner: MDCCornerTreatment;
31+
if (typeof cornerSize === 'object') {
32+
if (cornerFamily === CornerFamily.CUT) {
33+
corner = MDCCornerTreatment.cornerWithCutValueType(cornerSize.value, MDCCornerTreatmentValueType.Percentage);
34+
} else {
35+
corner = MDCCornerTreatment.cornerWithRadiusValueType(cornerSize.value, MDCCornerTreatmentValueType.Percentage);
36+
}
37+
} else {
38+
if (cornerFamily === CornerFamily.ROUNDED) {
39+
corner = MDCCornerTreatment.cornerWithCut(cornerSize);
40+
} else {
41+
corner = MDCCornerTreatment.cornerWithRadius(cornerSize);
42+
}
43+
}
44+
return corner;
45+
}
846
export class Themer {
947
appColorScheme: MDCSemanticColorScheme;
1048
appTypoScheme: MDCTypographyScheme;
@@ -102,6 +140,42 @@ export class Themer {
102140
// currentFont = currentFont.withFontFamily(args.fontFamily);
103141
// }
104142
}
143+
144+
_shapes: {
145+
[k: string]: MDCShapeScheme;
146+
} = {};
147+
getShape(key: string) {
148+
return this._shapes[key] || null;
149+
}
150+
createShape(key: string, options: ShapeProperties) {
151+
const shapeScheme = MDCShapeScheme.new();
152+
const shapeCategory = MDCShapeCategory.new();
153+
154+
if (options.cornerFamily && options.cornerSize !== undefined) {
155+
const corner = cornerTreatment(options.cornerFamily, options.cornerSize);
156+
shapeCategory.bottomLeftCorner = corner;
157+
shapeCategory.bottomRightCorner = corner;
158+
shapeCategory.topLeftCorner = corner;
159+
shapeCategory.topRightCorner = corner;
160+
}
161+
if (options.cornerFamilyBottomLeft && options.cornerSizeBottomLeft !== undefined) {
162+
shapeCategory.bottomLeftCorner = cornerTreatment(options.cornerFamilyBottomLeft, options.cornerSizeBottomLeft);
163+
}
164+
if (options.cornerFamilyBottomRight && options.cornerSizeBottomRight !== undefined) {
165+
shapeCategory.bottomRightCorner = cornerTreatment(options.cornerFamilyBottomRight, options.cornerSizeBottomRight);
166+
}
167+
168+
if (options.cornerFamilyTopLeft && options.cornerSizeTopLeft !== undefined) {
169+
shapeCategory.topLeftCorner = cornerTreatment(options.cornerFamilyTopLeft, options.cornerSizeTopLeft);
170+
}
171+
if (options.cornerFamilyTopRight && options.cornerSizeTopRight !== undefined) {
172+
shapeCategory.topRightCorner = cornerTreatment(options.cornerFamilyTopRight, options.cornerSizeTopRight);
173+
}
174+
shapeScheme.smallComponentShape = shapeCategory;
175+
shapeScheme.mediumComponentShape = shapeCategory;
176+
shapeScheme.largeComponentShape = shapeCategory;
177+
this._shapes[key] = shapeScheme;
178+
}
105179
}
106180

107181
export const themer = new Themer();

src/floatingactionbutton/floatingactionbutton-common.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export abstract class FloatingActionButtonBase extends Button {
3232
@cssProperty color: Color;
3333
@cssProperty rippleColor: Color;
3434
@cssProperty dynamicElevationOffset: number;
35+
@cssProperty shape: string;
3536

3637
public fabSize: string;
3738
public fabCustomSize: number;

src/floatingactionbutton/floatingactionbutton.android.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { dynamicElevationOffsetProperty, elevationProperty, rippleColorProperty } from '@nativescript-community/ui-material-core';
1+
import { dynamicElevationOffsetProperty, elevationProperty, rippleColorProperty, shapeProperty, themer } from '@nativescript-community/ui-material-core';
22
import { createStateListAnimator, isPostLollipop } from '@nativescript-community/ui-material-core/android/utils';
33
import { Background, Color, ImageSource, Length, backgroundInternalProperty, colorProperty } from '@nativescript/core';
44
import { textProperty } from '@nativescript/core/ui/text-base';
@@ -107,4 +107,8 @@ export class FloatingActionButton extends FloatingActionButtonBase {
107107
this.nativeViewProtected.shrink();
108108
}
109109
}
110+
[shapeProperty.setNative](shape: string) {
111+
const appearanceModel = themer.getShape(shape);
112+
this.nativeViewProtected.setShapeAppearanceModel(appearanceModel);
113+
}
110114
}

0 commit comments

Comments
 (0)