jsbox-cview 1.4.3 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/dialogs/dialog-sheet.ts +6 -3
- package/components/dynamic-contextmenu-view.ts +125 -0
- package/components/dynamic-preference-listview.ts +46 -27
- package/components/static-preference-listview.ts +118 -3
- package/dist/components/dialogs/dialog-sheet.js +4 -3
- package/dist/components/dynamic-contextmenu-view.js +95 -0
- package/dist/components/dynamic-preference-listview.js +52 -22
- package/dist/components/static-preference-listview.js +109 -1
- package/dist/index.js +1 -0
- package/dist/test/dynamic-contextmenu-view.js +69 -0
- package/dist/test/dynamic-preference-listview.js +11 -2
- package/dist/test/static-preference-listview.js +7 -0
- package/index.ts +1 -0
- package/package.json +2 -2
- package/test/dynamic-contextmenu-view.ts +70 -0
- package/test/dynamic-preference-listview.ts +11 -2
- package/test/static-preference-listview.ts +7 -0
|
@@ -13,6 +13,7 @@ import { Base } from "../base";
|
|
|
13
13
|
* @param doneHandler 完成时的回调
|
|
14
14
|
* @param presentMode 显示模式
|
|
15
15
|
* @param bgcolor 背景颜色
|
|
16
|
+
* @param doneButtonHidden 是否隐藏完成按钮, 默认为false,如果隐藏则需要自行实现完成逻辑
|
|
16
17
|
*/
|
|
17
18
|
export class DialogSheet extends Sheet<ContentView, UIView, UiTypes.ViewOptions> {
|
|
18
19
|
_props: {
|
|
@@ -21,6 +22,7 @@ export class DialogSheet extends Sheet<ContentView, UIView, UiTypes.ViewOptions>
|
|
|
21
22
|
doneHandler?: () => void;
|
|
22
23
|
presentMode?: number;
|
|
23
24
|
bgcolor?: UIColor;
|
|
25
|
+
doneButtonHidden?: boolean;
|
|
24
26
|
}
|
|
25
27
|
_done: boolean;
|
|
26
28
|
private _navbar?: CustomNavigationBar;
|
|
@@ -33,6 +35,7 @@ export class DialogSheet extends Sheet<ContentView, UIView, UiTypes.ViewOptions>
|
|
|
33
35
|
doneHandler?: () => void;
|
|
34
36
|
presentMode?: number;
|
|
35
37
|
bgcolor?: UIColor;
|
|
38
|
+
doneButtonHidden?: boolean;
|
|
36
39
|
}) {
|
|
37
40
|
super({
|
|
38
41
|
presentMode: props.presentMode || ($device.isIpad ? 2 : 1),
|
|
@@ -57,9 +60,9 @@ export class DialogSheet extends Sheet<ContentView, UIView, UiTypes.ViewOptions>
|
|
|
57
60
|
leftBarButtonItems: [
|
|
58
61
|
{ symbol: "xmark", handler: () => this.dismiss() }
|
|
59
62
|
],
|
|
60
|
-
rightBarButtonItems:
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
rightBarButtonItems: this._props.doneButtonHidden
|
|
64
|
+
? []
|
|
65
|
+
: [{ title: l10n("DONE"), handler: () => this.done() }]
|
|
63
66
|
}
|
|
64
67
|
});
|
|
65
68
|
this._props.cview._layout = (make, view) => {
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { Base } from "./base";
|
|
2
|
+
|
|
3
|
+
type MenuItem = {
|
|
4
|
+
title: string;
|
|
5
|
+
symbol: string;
|
|
6
|
+
handler: () => void;
|
|
7
|
+
destructive?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const RegisteredOCClassName: Set<string> = new Set()
|
|
11
|
+
|
|
12
|
+
function defineOCClass({ classname, menuList }: {
|
|
13
|
+
classname: string;
|
|
14
|
+
menuList: { title: string; items: MenuItem[] }[]
|
|
15
|
+
}) {
|
|
16
|
+
if (RegisteredOCClassName.has(classname)) return;
|
|
17
|
+
RegisteredOCClassName.add(classname);
|
|
18
|
+
$define({
|
|
19
|
+
type: classname + " : UIView <UIContextMenuInteractionDelegate>",
|
|
20
|
+
events: {
|
|
21
|
+
"contextMenuInteraction:configurationForMenuAtLocation:": (interacton: any, point: JBPoint) => {
|
|
22
|
+
console.log(interacton.$view().jsValue().info)
|
|
23
|
+
const menuIndex = (interacton.$view().jsValue().info?.menuIndex ?? 0) as number;
|
|
24
|
+
if (menuIndex < 0 || menuIndex >= menuList.length) return
|
|
25
|
+
return createContextMenuConfiguration(menuList[menuIndex]);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createUIAction(item: MenuItem) {
|
|
32
|
+
const action = $objc("UIAction").$actionWithTitle_image_identifier_handler(
|
|
33
|
+
item.title,
|
|
34
|
+
item.symbol,
|
|
35
|
+
null,
|
|
36
|
+
$block("void, UIAction *", () => item.handler())
|
|
37
|
+
);
|
|
38
|
+
if (item.destructive) action.$setAttributes(1 << 1);
|
|
39
|
+
return action;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
function createContextMenuConfiguration({ title, items }: { title: string, items: MenuItem[] }) {
|
|
43
|
+
return $objc("UIContextMenuConfiguration").$configurationWithIdentifier_previewProvider_actionProvider(
|
|
44
|
+
null,
|
|
45
|
+
null,
|
|
46
|
+
$block("UIMenu *, NSArray *", () => {
|
|
47
|
+
const actions = items.map(item => createUIAction(item))
|
|
48
|
+
return $objc("UIMenu").$menuWithTitle_children(title, actions);
|
|
49
|
+
})
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function createRuntimeView(classname: string, menuList: { title: string; items: MenuItem[] }[]) {
|
|
54
|
+
defineOCClass({ classname, menuList });
|
|
55
|
+
const view = $objc(classname).invoke("alloc.init");
|
|
56
|
+
const interaction = $objc("UIContextMenuInteraction")
|
|
57
|
+
.invoke("alloc")
|
|
58
|
+
.invoke("initWithDelegate", view);
|
|
59
|
+
view.$addInteraction(interaction);
|
|
60
|
+
return view;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 动态上下文菜单视图,此视图是为了弥补JSBox中无法动态调整上下文菜单的缺陷而设计的。
|
|
65
|
+
*
|
|
66
|
+
* 由于OC类的注册是全局性的,所以需要特殊的处理来避免重复注册类:对于使用同一套动态上下文菜单的View,应该注册为同一个类。
|
|
67
|
+
* 用menuList列表来记录所需的动态上下文菜单,通过props.info.menuIndex来指定当前视图需要使用的菜单。
|
|
68
|
+
*
|
|
69
|
+
* 此视图除了一般UIView的props, layout, events, views四个参数外,还有三个必须的特殊参数:
|
|
70
|
+
* 1. ocClassName: string OC类名,用于注册OC类,一个类名只能注册一次,重复注册会被忽略。
|
|
71
|
+
* 这和menuList是配套的,同一套menuList用同一个类名。
|
|
72
|
+
* 2. menuList: { title: string; items: MenuItem[] }[] 菜单列表,每个菜单项包含一个标题和一个MenuItem数组。
|
|
73
|
+
* 3. props.info: { menuIndex: number } 用于指定当前视图的菜单索引,从0开始。info中可以包含其他参数。
|
|
74
|
+
*
|
|
75
|
+
*/
|
|
76
|
+
export class DynamicContextMenuView extends Base<UILabelView, UiTypes.RuntimeOptions> {
|
|
77
|
+
private _menuList: { title: string; items: MenuItem[] }[];
|
|
78
|
+
_defineView: () => UiTypes.RuntimeOptions;
|
|
79
|
+
constructor({ ocClassName, menuList, props, layout, events, views = [] }: {
|
|
80
|
+
ocClassName: string;
|
|
81
|
+
menuList: { title: string; items: MenuItem[] }[];
|
|
82
|
+
props: UiTypes.BaseViewProps;
|
|
83
|
+
layout?: (make: MASConstraintMaker, view: UIView) => void;
|
|
84
|
+
events?: UiTypes.BaseViewEvents;
|
|
85
|
+
views: UiTypes.AllViewOptions[];
|
|
86
|
+
}) {
|
|
87
|
+
super();
|
|
88
|
+
if (!props.info || props.info?.menuIndex === undefined || props.info?.menuIndex === null) {
|
|
89
|
+
throw new Error("props.info.menuIndex is required");
|
|
90
|
+
}
|
|
91
|
+
if (typeof props.info.menuIndex !== "number") {
|
|
92
|
+
throw new Error("props.info.menuIndex must be a number");
|
|
93
|
+
}
|
|
94
|
+
if (props.info.menuIndex < 0 || props.info.menuIndex >= menuList.length) {
|
|
95
|
+
throw new Error("props.info.menuIndex is out of range");
|
|
96
|
+
}
|
|
97
|
+
this._menuList = menuList;
|
|
98
|
+
const runtimeView = createRuntimeView(ocClassName, menuList);
|
|
99
|
+
this._defineView = () => {
|
|
100
|
+
return {
|
|
101
|
+
type: "runtime",
|
|
102
|
+
props: {
|
|
103
|
+
...props,
|
|
104
|
+
id: this.id,
|
|
105
|
+
view: runtimeView
|
|
106
|
+
},
|
|
107
|
+
layout,
|
|
108
|
+
events,
|
|
109
|
+
views
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
set menuIndex(index: number) {
|
|
115
|
+
if (index < 0 || index >= this._menuList.length) {
|
|
116
|
+
throw new Error("menuIndex is out of range");
|
|
117
|
+
}
|
|
118
|
+
// 必须重新赋值info,否则info不会改变
|
|
119
|
+
this.view.info = { ...this.view.info, menuIndex: index };
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
get menuIndex(): number {
|
|
123
|
+
return this.view.info.menuIndex;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
@@ -10,12 +10,14 @@ import {
|
|
|
10
10
|
PrefsRowSlider,
|
|
11
11
|
PrefsRowList,
|
|
12
12
|
PrefsRowTab,
|
|
13
|
+
PrefsRowDate,
|
|
13
14
|
PrefsRowInfo,
|
|
14
15
|
PrefsRowInteractiveInfo,
|
|
15
16
|
PrefsRowLink,
|
|
16
17
|
PrefsRowAction,
|
|
17
18
|
selectableTypes,
|
|
18
|
-
excludedTypes
|
|
19
|
+
excludedTypes,
|
|
20
|
+
dateToString
|
|
19
21
|
} from "./static-preference-listview";
|
|
20
22
|
|
|
21
23
|
|
|
@@ -49,7 +51,7 @@ interface RequiredCunstomProps extends UiTypes.ListProps {
|
|
|
49
51
|
*
|
|
50
52
|
* 为了缓解上面的问题, 让修改布局无需调整源代码, 增加下列 props:
|
|
51
53
|
*
|
|
52
|
-
* - stringLeftInset?: number = 120 将同时作用于 string, number, integer, list,
|
|
54
|
+
* - stringLeftInset?: number = 120 将同时作用于 string, number, integer, list, date 但是由于后四者内容可控, 可视为只作用于 string
|
|
53
55
|
* - infoAndLinkLeftInset?: number = 120 作用于 info, link
|
|
54
56
|
* - sliderWidth?: number = 200 作用于 slider
|
|
55
57
|
* - tabWidth?: number = 200 作用于 tab
|
|
@@ -175,11 +177,10 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
175
177
|
events: {
|
|
176
178
|
changed: sender => {
|
|
177
179
|
const { section, row } = sender.info;
|
|
178
|
-
this._sections[section].rows[row].value =
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (events.changed)
|
|
182
|
-
events.changed(this.values);
|
|
180
|
+
this._sections[section].rows[row].value = sender.value;
|
|
181
|
+
const label = sender.next as UILabelView;
|
|
182
|
+
label.text = sender.value.toString();
|
|
183
|
+
if (events.changed) events.changed(this.values);
|
|
183
184
|
}
|
|
184
185
|
}
|
|
185
186
|
},
|
|
@@ -207,7 +208,9 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
207
208
|
{
|
|
208
209
|
type: "slider",
|
|
209
210
|
props: {
|
|
210
|
-
id: "slider"
|
|
211
|
+
id: "slider",
|
|
212
|
+
min: 0,
|
|
213
|
+
max: 1
|
|
211
214
|
},
|
|
212
215
|
layout: (make, view) => {
|
|
213
216
|
make.centerY.equalTo(view.super);
|
|
@@ -220,7 +223,7 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
220
223
|
const options = this._sections[section].rows[row] as PrefsRowSlider;
|
|
221
224
|
const label = sender.next as UILabelView;
|
|
222
225
|
label.text = this._handleSliderValue(
|
|
223
|
-
sender.value,
|
|
226
|
+
sender.value * (options.max ?? 1),
|
|
224
227
|
options.decimal,
|
|
225
228
|
options.min,
|
|
226
229
|
options.max
|
|
@@ -232,14 +235,12 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
232
235
|
this._sections[section].rows[
|
|
233
236
|
row
|
|
234
237
|
].value = this._handleSliderValue(
|
|
235
|
-
sender.value,
|
|
238
|
+
sender.value * (options.max ?? 1),
|
|
236
239
|
options.decimal,
|
|
237
240
|
options.min,
|
|
238
241
|
options.max
|
|
239
242
|
);
|
|
240
|
-
|
|
241
|
-
if (events.changed)
|
|
242
|
-
events.changed(this.values);
|
|
243
|
+
if (events.changed) events.changed(this.values);
|
|
243
244
|
}
|
|
244
245
|
}
|
|
245
246
|
},
|
|
@@ -270,11 +271,7 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
270
271
|
changed: sender => {
|
|
271
272
|
const { section, row } = sender.info;
|
|
272
273
|
this._sections[section].rows[row].value = sender.on;
|
|
273
|
-
|
|
274
|
-
this.view.data = this._map(this._sections);
|
|
275
|
-
if (events.changed)
|
|
276
|
-
events.changed(this.values);
|
|
277
|
-
});
|
|
274
|
+
if (events.changed) events.changed(this.values);
|
|
278
275
|
}
|
|
279
276
|
}
|
|
280
277
|
},
|
|
@@ -293,11 +290,7 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
293
290
|
changed: sender => {
|
|
294
291
|
const { section, row } = sender.info;
|
|
295
292
|
this._sections[section].rows[row].value = sender.index;
|
|
296
|
-
|
|
297
|
-
this.view.data = this._map(this._sections);
|
|
298
|
-
if (events.changed)
|
|
299
|
-
events.changed(this.values);
|
|
300
|
-
});
|
|
293
|
+
if (events.changed) events.changed(this.values);
|
|
301
294
|
}
|
|
302
295
|
}
|
|
303
296
|
},
|
|
@@ -383,6 +376,23 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
383
376
|
});
|
|
384
377
|
break;
|
|
385
378
|
}
|
|
379
|
+
case "date": {
|
|
380
|
+
const props: any = {}
|
|
381
|
+
if (row.value) props.date = row.value;
|
|
382
|
+
if (row.min) props.min = row.min;
|
|
383
|
+
if (row.max) props.max = row.max;
|
|
384
|
+
if (row.mode) props.mode = row.mode;
|
|
385
|
+
if (row.interval) props.interval = row.interval;
|
|
386
|
+
$picker.date({
|
|
387
|
+
props: props,
|
|
388
|
+
handler: (date: Date) => {
|
|
389
|
+
row.value = date;
|
|
390
|
+
sender.data = this._map(this._sections);
|
|
391
|
+
if (events.changed) events.changed(this.values);
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
386
396
|
case "interactive-info": {
|
|
387
397
|
if (row.copyable) {
|
|
388
398
|
$ui.alert({
|
|
@@ -465,7 +475,7 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
465
475
|
text: options.title,
|
|
466
476
|
textColor: options.titleColor || $color("primaryText")
|
|
467
477
|
}, // 标题, 同时用于action
|
|
468
|
-
label_and_chevron: { hidden: true }, // 用于string, number, integer, list
|
|
478
|
+
label_and_chevron: { hidden: true }, // 用于string, number, integer, list, date
|
|
469
479
|
number_and_stepper: { hidden: true }, // 用于stepper
|
|
470
480
|
slider_and_number: { hidden: true }, // 用于slider
|
|
471
481
|
switch: { hidden: true }, // 用于boolean
|
|
@@ -539,10 +549,10 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
539
549
|
text: adjustedValue
|
|
540
550
|
};
|
|
541
551
|
data.slider = {
|
|
542
|
-
value: adjustedValue,
|
|
552
|
+
value: adjustedValue / (n.max ?? 1),
|
|
543
553
|
info: { section: sectionIndex, row: rowIndex, key: n.key },
|
|
544
|
-
min: n.min,
|
|
545
|
-
max: n.max,
|
|
554
|
+
//min: n.min, // 不可用,否则会出现slider滑动结束变为0点的bug
|
|
555
|
+
//max: n.max,
|
|
546
556
|
minColor: n.minColor || $color("systemLink"),
|
|
547
557
|
maxColor: n.maxColor,
|
|
548
558
|
thumbColor: n.thumbColor
|
|
@@ -566,6 +576,15 @@ export class DynamicPreferenceListView extends Base<UIListView, UiTypes.ListOpti
|
|
|
566
576
|
};
|
|
567
577
|
break;
|
|
568
578
|
}
|
|
579
|
+
case "date": {
|
|
580
|
+
data.label_and_chevron.hidden = false;
|
|
581
|
+
data.label_before_chevron = {
|
|
582
|
+
hidden: false,
|
|
583
|
+
textColor: $color("secondaryText"),
|
|
584
|
+
text: dateToString(n.mode || 2, n.value)
|
|
585
|
+
};
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
569
588
|
case "info": {
|
|
570
589
|
data.label_info_link = {
|
|
571
590
|
hidden: false,
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Base } from "./base";
|
|
2
2
|
import { getTextWidth } from "../utils/uitools";
|
|
3
3
|
|
|
4
|
-
type PreferenceCellTypes = "string" | "number" | "integer" | "stepper" | "boolean" | "slider" | "list" | "tab" | "info" | "interactive-info" | "link" | "action";
|
|
4
|
+
type PreferenceCellTypes = "string" | "number" | "integer" | "stepper" | "boolean" | "slider" | "list" | "tab" | "date" | "info" | "interactive-info" | "link" | "action";
|
|
5
5
|
|
|
6
6
|
export interface PreferenceSection {
|
|
7
7
|
title: string;
|
|
8
8
|
rows: PrefsRow[]
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export type PrefsRow = PrefsRowString | PrefsRowNumber | PrefsRowInteger | PrefsRowStepper | PrefsRowBoolean | PrefsRowSlider | PrefsRowList | PrefsRowTab | PrefsRowInfo | PrefsRowInteractiveInfo | PrefsRowLink | PrefsRowAction;
|
|
11
|
+
export type PrefsRow = PrefsRowString | PrefsRowNumber | PrefsRowInteger | PrefsRowStepper | PrefsRowBoolean | PrefsRowSlider | PrefsRowList | PrefsRowTab | PrefsRowDate | PrefsRowInfo | PrefsRowInteractiveInfo | PrefsRowLink | PrefsRowAction;
|
|
12
12
|
|
|
13
13
|
interface PrefsRowBase {
|
|
14
14
|
type: PreferenceCellTypes;
|
|
@@ -80,6 +80,15 @@ export interface PrefsRowTab extends PrefsRowBase {
|
|
|
80
80
|
items: string[];
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
export interface PrefsRowDate extends PrefsRowBase {
|
|
84
|
+
type: "date";
|
|
85
|
+
value?: Date;
|
|
86
|
+
min?: Date;
|
|
87
|
+
max?: Date;
|
|
88
|
+
mode?: number;
|
|
89
|
+
interval?: number;
|
|
90
|
+
}
|
|
91
|
+
|
|
83
92
|
export interface PrefsRowInfo extends PrefsRowBase {
|
|
84
93
|
type: "info";
|
|
85
94
|
value?: string;
|
|
@@ -108,6 +117,7 @@ export const selectableTypes = [
|
|
|
108
117
|
"integer",
|
|
109
118
|
"stepper",
|
|
110
119
|
"list",
|
|
120
|
+
"date",
|
|
111
121
|
"interactive-info",
|
|
112
122
|
"link",
|
|
113
123
|
"action"
|
|
@@ -122,7 +132,7 @@ export const excludedTypes = [
|
|
|
122
132
|
|
|
123
133
|
type PreferenceValues = { [key: string]: any };
|
|
124
134
|
|
|
125
|
-
type AllCells = StringCell | NumberCell | IntegerCell | StepperCell | BooleanCell | SliderCell | ListCell | TabCell | InteractiveInfoCell | InfoCell | LinkCell | ActionCell;
|
|
135
|
+
type AllCells = StringCell | NumberCell | IntegerCell | StepperCell | BooleanCell | SliderCell | ListCell | TabCell | DateCell | InteractiveInfoCell | InfoCell | LinkCell | ActionCell;
|
|
126
136
|
|
|
127
137
|
abstract class Cell extends Base<UIView, UiTypes.ViewOptions> {
|
|
128
138
|
abstract _type: string;
|
|
@@ -638,6 +648,85 @@ class TabCell extends Cell {
|
|
|
638
648
|
}
|
|
639
649
|
}
|
|
640
650
|
|
|
651
|
+
export function dateToString(mode: number, date?: Date) {
|
|
652
|
+
if (!date) return ""
|
|
653
|
+
const year = date.getFullYear();
|
|
654
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
655
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
656
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
657
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
658
|
+
if (mode === 0 || mode === 3) {
|
|
659
|
+
return `${hours}:${minutes}`;
|
|
660
|
+
} else if (mode === 1) {
|
|
661
|
+
return `${year}-${month}-${day}`;
|
|
662
|
+
} else {
|
|
663
|
+
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
class DateCell extends Cell {
|
|
668
|
+
readonly _type = "date";
|
|
669
|
+
_mode: number;
|
|
670
|
+
_interval?: number;
|
|
671
|
+
_min?: Date;
|
|
672
|
+
_max?: Date;
|
|
673
|
+
constructor(props: PrefsRowDate, values: PreferenceValues) {
|
|
674
|
+
super(props, values);
|
|
675
|
+
const { mode, min, max, interval } = props;
|
|
676
|
+
this._mode = mode || 2;
|
|
677
|
+
this._min = min;
|
|
678
|
+
this._max = max;
|
|
679
|
+
this._interval = interval;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
_defineValueView(): UiTypes.ViewOptions {
|
|
683
|
+
return {
|
|
684
|
+
type: "view",
|
|
685
|
+
props: {},
|
|
686
|
+
layout: (make, view) => {
|
|
687
|
+
make.top.bottom.inset(0);
|
|
688
|
+
make.left.equalTo(view.prev.right).inset(10);
|
|
689
|
+
make.right.inset(15);
|
|
690
|
+
},
|
|
691
|
+
views: [
|
|
692
|
+
{
|
|
693
|
+
type: "image",
|
|
694
|
+
props: {
|
|
695
|
+
symbol: "chevron.right",
|
|
696
|
+
tintColor: $color("lightGray", "darkGray"),
|
|
697
|
+
contentMode: 1
|
|
698
|
+
},
|
|
699
|
+
layout: (make, view) => {
|
|
700
|
+
make.centerY.equalTo(view.super);
|
|
701
|
+
make.size.equalTo($size(17, 17));
|
|
702
|
+
make.right.inset(0);
|
|
703
|
+
}
|
|
704
|
+
},
|
|
705
|
+
{
|
|
706
|
+
type: "label",
|
|
707
|
+
props: {
|
|
708
|
+
id: "label",
|
|
709
|
+
text: dateToString(this._mode, this._value),
|
|
710
|
+
textColor: $color("secondaryText"),
|
|
711
|
+
align: $align.right
|
|
712
|
+
},
|
|
713
|
+
layout: (make, view) => {
|
|
714
|
+
make.centerY.equalTo(view.super);
|
|
715
|
+
make.left.inset(0);
|
|
716
|
+
make.right.equalTo(view.prev.left).inset(5);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
]
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
_handleValue(date: Date) {
|
|
724
|
+
const label = this.view.get("label") as UILabelView;
|
|
725
|
+
label.text = dateToString(this._mode, date);
|
|
726
|
+
return date;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
641
730
|
class InfoCell extends Cell {
|
|
642
731
|
readonly _type = "info";
|
|
643
732
|
constructor(props: PrefsRowInfo, values: PreferenceValues) {
|
|
@@ -853,6 +942,14 @@ class ActionCell extends Cell {
|
|
|
853
942
|
* - value?: number 即 index, -1 时为不选
|
|
854
943
|
* - items?: string[]
|
|
855
944
|
*
|
|
945
|
+
* - date:
|
|
946
|
+
*
|
|
947
|
+
* - value?: Date
|
|
948
|
+
* - min?: Date
|
|
949
|
+
* - max?: Date
|
|
950
|
+
* - mode?: number = 2
|
|
951
|
+
* - interval?: number
|
|
952
|
+
*
|
|
856
953
|
* - info:
|
|
857
954
|
*
|
|
858
955
|
* - value?: string
|
|
@@ -985,6 +1082,22 @@ export class PreferenceListView extends Base<UIListView, UiTypes.ListOptions> {
|
|
|
985
1082
|
});
|
|
986
1083
|
break;
|
|
987
1084
|
}
|
|
1085
|
+
case "date": {
|
|
1086
|
+
const props: any = {}
|
|
1087
|
+
if (cell.value) props.date = cell.value;
|
|
1088
|
+
if (cell._min) props.min = cell._min;
|
|
1089
|
+
if (cell._max) props.max = cell._max;
|
|
1090
|
+
if (cell._mode) props.mode = cell._mode;
|
|
1091
|
+
if (cell._interval) props.interval = cell._interval;
|
|
1092
|
+
$picker.date({
|
|
1093
|
+
props: props,
|
|
1094
|
+
handler: (date: Date) => {
|
|
1095
|
+
cell.value = date;
|
|
1096
|
+
if (cell._changedEvent) cell._changedEvent();
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
break;
|
|
1100
|
+
}
|
|
988
1101
|
case "interactive-info": {
|
|
989
1102
|
if (cell._copyable) {
|
|
990
1103
|
$ui.alert({
|
|
@@ -1045,6 +1158,8 @@ export class PreferenceListView extends Base<UIListView, UiTypes.ListOptions> {
|
|
|
1045
1158
|
return new ListCell(props, this._values);
|
|
1046
1159
|
case "tab":
|
|
1047
1160
|
return new TabCell(props, this._values);
|
|
1161
|
+
case "date":
|
|
1162
|
+
return new DateCell(props, this._values);
|
|
1048
1163
|
case "info":
|
|
1049
1164
|
return new InfoCell(props, this._values);
|
|
1050
1165
|
case "interactive-info":
|
|
@@ -13,6 +13,7 @@ const single_views_1 = require("../single-views");
|
|
|
13
13
|
* @param doneHandler 完成时的回调
|
|
14
14
|
* @param presentMode 显示模式
|
|
15
15
|
* @param bgcolor 背景颜色
|
|
16
|
+
* @param doneButtonHidden 是否隐藏完成按钮, 默认为false,如果隐藏则需要自行实现完成逻辑
|
|
16
17
|
*/
|
|
17
18
|
class DialogSheet extends sheet_1.Sheet {
|
|
18
19
|
constructor(props) {
|
|
@@ -38,9 +39,9 @@ class DialogSheet extends sheet_1.Sheet {
|
|
|
38
39
|
leftBarButtonItems: [
|
|
39
40
|
{ symbol: "xmark", handler: () => this.dismiss() }
|
|
40
41
|
],
|
|
41
|
-
rightBarButtonItems:
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
rightBarButtonItems: this._props.doneButtonHidden
|
|
43
|
+
? []
|
|
44
|
+
: [{ title: (0, l10n_1.l10n)("DONE"), handler: () => this.done() }]
|
|
44
45
|
}
|
|
45
46
|
});
|
|
46
47
|
this._props.cview._layout = (make, view) => {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DynamicContextMenuView = void 0;
|
|
4
|
+
const base_1 = require("./base");
|
|
5
|
+
const RegisteredOCClassName = new Set();
|
|
6
|
+
function defineOCClass({ classname, menuList }) {
|
|
7
|
+
if (RegisteredOCClassName.has(classname))
|
|
8
|
+
return;
|
|
9
|
+
RegisteredOCClassName.add(classname);
|
|
10
|
+
$define({
|
|
11
|
+
type: classname + " : UIView <UIContextMenuInteractionDelegate>",
|
|
12
|
+
events: {
|
|
13
|
+
"contextMenuInteraction:configurationForMenuAtLocation:": (interacton, point) => {
|
|
14
|
+
var _a, _b;
|
|
15
|
+
console.log(interacton.$view().jsValue().info);
|
|
16
|
+
const menuIndex = ((_b = (_a = interacton.$view().jsValue().info) === null || _a === void 0 ? void 0 : _a.menuIndex) !== null && _b !== void 0 ? _b : 0);
|
|
17
|
+
if (menuIndex < 0 || menuIndex >= menuList.length)
|
|
18
|
+
return;
|
|
19
|
+
return createContextMenuConfiguration(menuList[menuIndex]);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function createUIAction(item) {
|
|
25
|
+
const action = $objc("UIAction").$actionWithTitle_image_identifier_handler(item.title, item.symbol, null, $block("void, UIAction *", () => item.handler()));
|
|
26
|
+
if (item.destructive)
|
|
27
|
+
action.$setAttributes(1 << 1);
|
|
28
|
+
return action;
|
|
29
|
+
}
|
|
30
|
+
;
|
|
31
|
+
function createContextMenuConfiguration({ title, items }) {
|
|
32
|
+
return $objc("UIContextMenuConfiguration").$configurationWithIdentifier_previewProvider_actionProvider(null, null, $block("UIMenu *, NSArray *", () => {
|
|
33
|
+
const actions = items.map(item => createUIAction(item));
|
|
34
|
+
return $objc("UIMenu").$menuWithTitle_children(title, actions);
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
37
|
+
function createRuntimeView(classname, menuList) {
|
|
38
|
+
defineOCClass({ classname, menuList });
|
|
39
|
+
const view = $objc(classname).invoke("alloc.init");
|
|
40
|
+
const interaction = $objc("UIContextMenuInteraction")
|
|
41
|
+
.invoke("alloc")
|
|
42
|
+
.invoke("initWithDelegate", view);
|
|
43
|
+
view.$addInteraction(interaction);
|
|
44
|
+
return view;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 动态上下文菜单视图,此视图是为了弥补JSBox中无法动态调整上下文菜单的缺陷而设计的。
|
|
48
|
+
*
|
|
49
|
+
* 由于OC类的注册是全局性的,所以需要特殊的处理来避免重复注册类:对于使用同一套动态上下文菜单的View,应该注册为同一个类。
|
|
50
|
+
* 用menuList列表来记录所需的动态上下文菜单,通过props.info.menuIndex来指定当前视图需要使用的菜单。
|
|
51
|
+
*
|
|
52
|
+
* 此视图除了一般UIView的props, layout, events, views四个参数外,还有三个必须的特殊参数:
|
|
53
|
+
* 1. ocClassName: string OC类名,用于注册OC类,一个类名只能注册一次,重复注册会被忽略。
|
|
54
|
+
* 这和menuList是配套的,同一套menuList用同一个类名。
|
|
55
|
+
* 2. menuList: { title: string; items: MenuItem[] }[] 菜单列表,每个菜单项包含一个标题和一个MenuItem数组。
|
|
56
|
+
* 3. props.info: { menuIndex: number } 用于指定当前视图的菜单索引,从0开始。info中可以包含其他参数。
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
class DynamicContextMenuView extends base_1.Base {
|
|
60
|
+
constructor({ ocClassName, menuList, props, layout, events, views = [] }) {
|
|
61
|
+
var _a, _b;
|
|
62
|
+
super();
|
|
63
|
+
if (!props.info || ((_a = props.info) === null || _a === void 0 ? void 0 : _a.menuIndex) === undefined || ((_b = props.info) === null || _b === void 0 ? void 0 : _b.menuIndex) === null) {
|
|
64
|
+
throw new Error("props.info.menuIndex is required");
|
|
65
|
+
}
|
|
66
|
+
if (typeof props.info.menuIndex !== "number") {
|
|
67
|
+
throw new Error("props.info.menuIndex must be a number");
|
|
68
|
+
}
|
|
69
|
+
if (props.info.menuIndex < 0 || props.info.menuIndex >= menuList.length) {
|
|
70
|
+
throw new Error("props.info.menuIndex is out of range");
|
|
71
|
+
}
|
|
72
|
+
this._menuList = menuList;
|
|
73
|
+
const runtimeView = createRuntimeView(ocClassName, menuList);
|
|
74
|
+
this._defineView = () => {
|
|
75
|
+
return {
|
|
76
|
+
type: "runtime",
|
|
77
|
+
props: Object.assign(Object.assign({}, props), { id: this.id, view: runtimeView }),
|
|
78
|
+
layout,
|
|
79
|
+
events,
|
|
80
|
+
views
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
set menuIndex(index) {
|
|
85
|
+
if (index < 0 || index >= this._menuList.length) {
|
|
86
|
+
throw new Error("menuIndex is out of range");
|
|
87
|
+
}
|
|
88
|
+
// 必须重新赋值info,否则info不会改变
|
|
89
|
+
this.view.info = Object.assign(Object.assign({}, this.view.info), { menuIndex: index });
|
|
90
|
+
}
|
|
91
|
+
get menuIndex() {
|
|
92
|
+
return this.view.info.menuIndex;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.DynamicContextMenuView = DynamicContextMenuView;
|
|
@@ -19,7 +19,7 @@ const static_preference_listview_1 = require("./static-preference-listview");
|
|
|
19
19
|
*
|
|
20
20
|
* 为了缓解上面的问题, 让修改布局无需调整源代码, 增加下列 props:
|
|
21
21
|
*
|
|
22
|
-
* - stringLeftInset?: number = 120 将同时作用于 string, number, integer, list,
|
|
22
|
+
* - stringLeftInset?: number = 120 将同时作用于 string, number, integer, list, date 但是由于后四者内容可控, 可视为只作用于 string
|
|
23
23
|
* - infoAndLinkLeftInset?: number = 120 作用于 info, link
|
|
24
24
|
* - sliderWidth?: number = 200 作用于 slider
|
|
25
25
|
* - tabWidth?: number = 200 作用于 tab
|
|
@@ -124,9 +124,9 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
124
124
|
events: {
|
|
125
125
|
changed: sender => {
|
|
126
126
|
const { section, row } = sender.info;
|
|
127
|
-
this._sections[section].rows[row].value =
|
|
128
|
-
|
|
129
|
-
|
|
127
|
+
this._sections[section].rows[row].value = sender.value;
|
|
128
|
+
const label = sender.next;
|
|
129
|
+
label.text = sender.value.toString();
|
|
130
130
|
if (events.changed)
|
|
131
131
|
events.changed(this.values);
|
|
132
132
|
}
|
|
@@ -156,7 +156,9 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
156
156
|
{
|
|
157
157
|
type: "slider",
|
|
158
158
|
props: {
|
|
159
|
-
id: "slider"
|
|
159
|
+
id: "slider",
|
|
160
|
+
min: 0,
|
|
161
|
+
max: 1
|
|
160
162
|
},
|
|
161
163
|
layout: (make, view) => {
|
|
162
164
|
make.centerY.equalTo(view.super);
|
|
@@ -165,16 +167,17 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
165
167
|
},
|
|
166
168
|
events: {
|
|
167
169
|
changed: sender => {
|
|
170
|
+
var _a;
|
|
168
171
|
const { section, row } = sender.info;
|
|
169
172
|
const options = this._sections[section].rows[row];
|
|
170
173
|
const label = sender.next;
|
|
171
|
-
label.text = this._handleSliderValue(sender.value, options.decimal, options.min, options.max).toString();
|
|
174
|
+
label.text = this._handleSliderValue(sender.value * ((_a = options.max) !== null && _a !== void 0 ? _a : 1), options.decimal, options.min, options.max).toString();
|
|
172
175
|
},
|
|
173
176
|
touchesEnded: sender => {
|
|
177
|
+
var _a;
|
|
174
178
|
const { section, row } = sender.info;
|
|
175
179
|
const options = this._sections[section].rows[row];
|
|
176
|
-
this._sections[section].rows[row].value = this._handleSliderValue(sender.value, options.decimal, options.min, options.max);
|
|
177
|
-
this.view.data = this._map(this._sections);
|
|
180
|
+
this._sections[section].rows[row].value = this._handleSliderValue(sender.value * ((_a = options.max) !== null && _a !== void 0 ? _a : 1), options.decimal, options.min, options.max);
|
|
178
181
|
if (events.changed)
|
|
179
182
|
events.changed(this.values);
|
|
180
183
|
}
|
|
@@ -207,11 +210,8 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
207
210
|
changed: sender => {
|
|
208
211
|
const { section, row } = sender.info;
|
|
209
212
|
this._sections[section].rows[row].value = sender.on;
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
if (events.changed)
|
|
213
|
-
events.changed(this.values);
|
|
214
|
-
});
|
|
213
|
+
if (events.changed)
|
|
214
|
+
events.changed(this.values);
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
},
|
|
@@ -230,11 +230,8 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
230
230
|
changed: sender => {
|
|
231
231
|
const { section, row } = sender.info;
|
|
232
232
|
this._sections[section].rows[row].value = sender.index;
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (events.changed)
|
|
236
|
-
events.changed(this.values);
|
|
237
|
-
});
|
|
233
|
+
if (events.changed)
|
|
234
|
+
events.changed(this.values);
|
|
238
235
|
}
|
|
239
236
|
}
|
|
240
237
|
},
|
|
@@ -330,6 +327,29 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
330
327
|
});
|
|
331
328
|
break;
|
|
332
329
|
}
|
|
330
|
+
case "date": {
|
|
331
|
+
const props = {};
|
|
332
|
+
if (row.value)
|
|
333
|
+
props.date = row.value;
|
|
334
|
+
if (row.min)
|
|
335
|
+
props.min = row.min;
|
|
336
|
+
if (row.max)
|
|
337
|
+
props.max = row.max;
|
|
338
|
+
if (row.mode)
|
|
339
|
+
props.mode = row.mode;
|
|
340
|
+
if (row.interval)
|
|
341
|
+
props.interval = row.interval;
|
|
342
|
+
$picker.date({
|
|
343
|
+
props: props,
|
|
344
|
+
handler: (date) => {
|
|
345
|
+
row.value = date;
|
|
346
|
+
sender.data = this._map(this._sections);
|
|
347
|
+
if (events.changed)
|
|
348
|
+
events.changed(this.values);
|
|
349
|
+
}
|
|
350
|
+
});
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
333
353
|
case "interactive-info": {
|
|
334
354
|
if (row.copyable) {
|
|
335
355
|
$ui.alert({
|
|
@@ -420,7 +440,7 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
420
440
|
text: options.title,
|
|
421
441
|
textColor: options.titleColor || $color("primaryText")
|
|
422
442
|
}, // 标题, 同时用于action
|
|
423
|
-
label_and_chevron: { hidden: true }, // 用于string, number, integer, list
|
|
443
|
+
label_and_chevron: { hidden: true }, // 用于string, number, integer, list, date
|
|
424
444
|
number_and_stepper: { hidden: true }, // 用于stepper
|
|
425
445
|
slider_and_number: { hidden: true }, // 用于slider
|
|
426
446
|
switch: { hidden: true }, // 用于boolean
|
|
@@ -431,6 +451,7 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
431
451
|
return sections.map((section, sectionIndex) => ({
|
|
432
452
|
title: section.title,
|
|
433
453
|
rows: section.rows.map((n, rowIndex) => {
|
|
454
|
+
var _a;
|
|
434
455
|
const data = generateDefaultRow(n);
|
|
435
456
|
switch (n.type) {
|
|
436
457
|
case "string": {
|
|
@@ -489,10 +510,10 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
489
510
|
text: adjustedValue
|
|
490
511
|
};
|
|
491
512
|
data.slider = {
|
|
492
|
-
value: adjustedValue,
|
|
513
|
+
value: adjustedValue / ((_a = n.max) !== null && _a !== void 0 ? _a : 1),
|
|
493
514
|
info: { section: sectionIndex, row: rowIndex, key: n.key },
|
|
494
|
-
min: n.min,
|
|
495
|
-
max: n.max,
|
|
515
|
+
//min: n.min, // 不可用,否则会出现slider滑动结束变为0点的bug
|
|
516
|
+
//max: n.max,
|
|
496
517
|
minColor: n.minColor || $color("systemLink"),
|
|
497
518
|
maxColor: n.maxColor,
|
|
498
519
|
thumbColor: n.thumbColor
|
|
@@ -516,6 +537,15 @@ class DynamicPreferenceListView extends base_1.Base {
|
|
|
516
537
|
};
|
|
517
538
|
break;
|
|
518
539
|
}
|
|
540
|
+
case "date": {
|
|
541
|
+
data.label_and_chevron.hidden = false;
|
|
542
|
+
data.label_before_chevron = {
|
|
543
|
+
hidden: false,
|
|
544
|
+
textColor: $color("secondaryText"),
|
|
545
|
+
text: (0, static_preference_listview_1.dateToString)(n.mode || 2, n.value)
|
|
546
|
+
};
|
|
547
|
+
break;
|
|
548
|
+
}
|
|
519
549
|
case "info": {
|
|
520
550
|
data.label_info_link = {
|
|
521
551
|
hidden: false,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PreferenceListView = exports.excludedTypes = exports.selectableTypes = void 0;
|
|
3
|
+
exports.PreferenceListView = exports.dateToString = exports.excludedTypes = exports.selectableTypes = void 0;
|
|
4
4
|
const base_1 = require("./base");
|
|
5
5
|
const uitools_1 = require("../utils/uitools");
|
|
6
6
|
exports.selectableTypes = [
|
|
@@ -9,6 +9,7 @@ exports.selectableTypes = [
|
|
|
9
9
|
"integer",
|
|
10
10
|
"stepper",
|
|
11
11
|
"list",
|
|
12
|
+
"date",
|
|
12
13
|
"interactive-info",
|
|
13
14
|
"link",
|
|
14
15
|
"action"
|
|
@@ -468,6 +469,81 @@ class TabCell extends Cell {
|
|
|
468
469
|
return num;
|
|
469
470
|
}
|
|
470
471
|
}
|
|
472
|
+
function dateToString(mode, date) {
|
|
473
|
+
if (!date)
|
|
474
|
+
return "";
|
|
475
|
+
const year = date.getFullYear();
|
|
476
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
477
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
478
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
479
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
480
|
+
if (mode === 0 || mode === 3) {
|
|
481
|
+
return `${hours}:${minutes}`;
|
|
482
|
+
}
|
|
483
|
+
else if (mode === 1) {
|
|
484
|
+
return `${year}-${month}-${day}`;
|
|
485
|
+
}
|
|
486
|
+
else {
|
|
487
|
+
return `${year}-${month}-${day} ${hours}:${minutes}`;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
exports.dateToString = dateToString;
|
|
491
|
+
class DateCell extends Cell {
|
|
492
|
+
constructor(props, values) {
|
|
493
|
+
super(props, values);
|
|
494
|
+
this._type = "date";
|
|
495
|
+
const { mode, min, max, interval } = props;
|
|
496
|
+
this._mode = mode || 2;
|
|
497
|
+
this._min = min;
|
|
498
|
+
this._max = max;
|
|
499
|
+
this._interval = interval;
|
|
500
|
+
}
|
|
501
|
+
_defineValueView() {
|
|
502
|
+
return {
|
|
503
|
+
type: "view",
|
|
504
|
+
props: {},
|
|
505
|
+
layout: (make, view) => {
|
|
506
|
+
make.top.bottom.inset(0);
|
|
507
|
+
make.left.equalTo(view.prev.right).inset(10);
|
|
508
|
+
make.right.inset(15);
|
|
509
|
+
},
|
|
510
|
+
views: [
|
|
511
|
+
{
|
|
512
|
+
type: "image",
|
|
513
|
+
props: {
|
|
514
|
+
symbol: "chevron.right",
|
|
515
|
+
tintColor: $color("lightGray", "darkGray"),
|
|
516
|
+
contentMode: 1
|
|
517
|
+
},
|
|
518
|
+
layout: (make, view) => {
|
|
519
|
+
make.centerY.equalTo(view.super);
|
|
520
|
+
make.size.equalTo($size(17, 17));
|
|
521
|
+
make.right.inset(0);
|
|
522
|
+
}
|
|
523
|
+
},
|
|
524
|
+
{
|
|
525
|
+
type: "label",
|
|
526
|
+
props: {
|
|
527
|
+
id: "label",
|
|
528
|
+
text: dateToString(this._mode, this._value),
|
|
529
|
+
textColor: $color("secondaryText"),
|
|
530
|
+
align: $align.right
|
|
531
|
+
},
|
|
532
|
+
layout: (make, view) => {
|
|
533
|
+
make.centerY.equalTo(view.super);
|
|
534
|
+
make.left.inset(0);
|
|
535
|
+
make.right.equalTo(view.prev.left).inset(5);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
]
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
_handleValue(date) {
|
|
542
|
+
const label = this.view.get("label");
|
|
543
|
+
label.text = dateToString(this._mode, date);
|
|
544
|
+
return date;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
471
547
|
class InfoCell extends Cell {
|
|
472
548
|
constructor(props, values) {
|
|
473
549
|
super(props, values);
|
|
@@ -668,6 +744,14 @@ class ActionCell extends Cell {
|
|
|
668
744
|
* - value?: number 即 index, -1 时为不选
|
|
669
745
|
* - items?: string[]
|
|
670
746
|
*
|
|
747
|
+
* - date:
|
|
748
|
+
*
|
|
749
|
+
* - value?: Date
|
|
750
|
+
* - min?: Date
|
|
751
|
+
* - max?: Date
|
|
752
|
+
* - mode?: number = 2
|
|
753
|
+
* - interval?: number
|
|
754
|
+
*
|
|
671
755
|
* - info:
|
|
672
756
|
*
|
|
673
757
|
* - value?: string
|
|
@@ -782,6 +866,28 @@ class PreferenceListView extends base_1.Base {
|
|
|
782
866
|
});
|
|
783
867
|
break;
|
|
784
868
|
}
|
|
869
|
+
case "date": {
|
|
870
|
+
const props = {};
|
|
871
|
+
if (cell.value)
|
|
872
|
+
props.date = cell.value;
|
|
873
|
+
if (cell._min)
|
|
874
|
+
props.min = cell._min;
|
|
875
|
+
if (cell._max)
|
|
876
|
+
props.max = cell._max;
|
|
877
|
+
if (cell._mode)
|
|
878
|
+
props.mode = cell._mode;
|
|
879
|
+
if (cell._interval)
|
|
880
|
+
props.interval = cell._interval;
|
|
881
|
+
$picker.date({
|
|
882
|
+
props: props,
|
|
883
|
+
handler: (date) => {
|
|
884
|
+
cell.value = date;
|
|
885
|
+
if (cell._changedEvent)
|
|
886
|
+
cell._changedEvent();
|
|
887
|
+
}
|
|
888
|
+
});
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
785
891
|
case "interactive-info": {
|
|
786
892
|
if (cell._copyable) {
|
|
787
893
|
$ui.alert({
|
|
@@ -842,6 +948,8 @@ class PreferenceListView extends base_1.Base {
|
|
|
842
948
|
return new ListCell(props, this._values);
|
|
843
949
|
case "tab":
|
|
844
950
|
return new TabCell(props, this._values);
|
|
951
|
+
case "date":
|
|
952
|
+
return new DateCell(props, this._values);
|
|
845
953
|
case "info":
|
|
846
954
|
return new InfoCell(props, this._values);
|
|
847
955
|
case "interactive-info":
|
package/dist/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./components/base"), exports);
|
|
18
18
|
__exportStar(require("./components/custom-navigation-bar"), exports);
|
|
19
|
+
__exportStar(require("./components/dynamic-contextmenu-view"), exports);
|
|
19
20
|
__exportStar(require("./components/dynamic-itemsize-matrix"), exports);
|
|
20
21
|
__exportStar(require("./components/dynamic-preference-listview"), exports);
|
|
21
22
|
__exportStar(require("./components/dynamic-rowheight-list"), exports);
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const dynamic_contextmenu_view_1 = require("../components/dynamic-contextmenu-view");
|
|
4
|
+
const menuList = [
|
|
5
|
+
{
|
|
6
|
+
title: "菜单1",
|
|
7
|
+
items: [
|
|
8
|
+
{
|
|
9
|
+
title: "变成菜单1",
|
|
10
|
+
symbol: "plus",
|
|
11
|
+
handler: () => {
|
|
12
|
+
view.menuIndex = 0;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
title: "变成菜单2",
|
|
17
|
+
symbol: "plus",
|
|
18
|
+
destructive: true,
|
|
19
|
+
handler: () => {
|
|
20
|
+
view.menuIndex = 1;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
title: "菜单2",
|
|
27
|
+
items: [
|
|
28
|
+
{
|
|
29
|
+
title: "变成菜单1",
|
|
30
|
+
symbol: "plus",
|
|
31
|
+
handler: () => {
|
|
32
|
+
view.menuIndex = 0;
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
title: "变成菜单2",
|
|
37
|
+
symbol: "plus",
|
|
38
|
+
handler: () => {
|
|
39
|
+
view.menuIndex = 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
];
|
|
45
|
+
const view = new dynamic_contextmenu_view_1.DynamicContextMenuView({
|
|
46
|
+
ocClassName: "testView",
|
|
47
|
+
menuList,
|
|
48
|
+
props: {
|
|
49
|
+
info: {
|
|
50
|
+
menuIndex: 0
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
layout: (make, view) => {
|
|
54
|
+
make.center.equalTo(view.super);
|
|
55
|
+
make.size.equalTo($size(100, 100));
|
|
56
|
+
},
|
|
57
|
+
views: [{
|
|
58
|
+
type: "label",
|
|
59
|
+
props: {
|
|
60
|
+
text: "长按我",
|
|
61
|
+
textColor: $color("black"),
|
|
62
|
+
align: $align.center
|
|
63
|
+
},
|
|
64
|
+
layout: $layout.center
|
|
65
|
+
}]
|
|
66
|
+
});
|
|
67
|
+
$ui.render({
|
|
68
|
+
views: [view.definition]
|
|
69
|
+
});
|
|
@@ -49,7 +49,7 @@ const sections = [
|
|
|
49
49
|
value: 1,
|
|
50
50
|
decimal: 0,
|
|
51
51
|
min: 0,
|
|
52
|
-
max:
|
|
52
|
+
max: 2
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
type: "list",
|
|
@@ -64,6 +64,12 @@ const sections = [
|
|
|
64
64
|
key: "tab",
|
|
65
65
|
items: ["测试aaa", "测试bbb"],
|
|
66
66
|
value: 0
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: "date",
|
|
70
|
+
title: "date",
|
|
71
|
+
key: "date",
|
|
72
|
+
mode: 1
|
|
67
73
|
}
|
|
68
74
|
]
|
|
69
75
|
},
|
|
@@ -93,7 +99,10 @@ const v = new dynamic_preference_listview_1.DynamicPreferenceListView({
|
|
|
93
99
|
sections: sections,
|
|
94
100
|
layout: $layout.fill,
|
|
95
101
|
events: {
|
|
96
|
-
changed: (values) =>
|
|
102
|
+
changed: (values) => {
|
|
103
|
+
console.info(values);
|
|
104
|
+
console.info(values.date);
|
|
105
|
+
}
|
|
97
106
|
}
|
|
98
107
|
});
|
|
99
108
|
$ui.render({
|
package/index.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './components/base';
|
|
2
2
|
export * from './components/custom-navigation-bar';
|
|
3
|
+
export * from './components/dynamic-contextmenu-view';
|
|
3
4
|
export * from './components/dynamic-itemsize-matrix';
|
|
4
5
|
export * from './components/dynamic-preference-listview';
|
|
5
6
|
export * from './components/dynamic-rowheight-list';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jsbox-cview",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "为 JSBox 设计的微型框架",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -19,6 +19,6 @@
|
|
|
19
19
|
"devDependencies": {
|
|
20
20
|
"@types/node": "^20.11.17",
|
|
21
21
|
"browserify": "^17.0.0",
|
|
22
|
-
"jsbox-types": "^1.0.
|
|
22
|
+
"jsbox-types": "^1.0.30"
|
|
23
23
|
}
|
|
24
24
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { DynamicContextMenuView } from "../components/dynamic-contextmenu-view";
|
|
2
|
+
|
|
3
|
+
const menuList = [
|
|
4
|
+
{
|
|
5
|
+
title: "菜单1",
|
|
6
|
+
items: [
|
|
7
|
+
{
|
|
8
|
+
title: "变成菜单1",
|
|
9
|
+
symbol: "plus",
|
|
10
|
+
handler: () => {
|
|
11
|
+
view.menuIndex = 0;
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
title: "变成菜单2",
|
|
16
|
+
symbol: "plus",
|
|
17
|
+
destructive: true,
|
|
18
|
+
handler: () => {
|
|
19
|
+
view.menuIndex = 1;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
title: "菜单2",
|
|
26
|
+
items: [
|
|
27
|
+
{
|
|
28
|
+
title: "变成菜单1",
|
|
29
|
+
symbol: "plus",
|
|
30
|
+
handler: () => {
|
|
31
|
+
view.menuIndex = 0;
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
title: "变成菜单2",
|
|
36
|
+
symbol: "plus",
|
|
37
|
+
handler: () => {
|
|
38
|
+
view.menuIndex = 1;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
const view = new DynamicContextMenuView({
|
|
46
|
+
ocClassName: "testView",
|
|
47
|
+
menuList,
|
|
48
|
+
props: {
|
|
49
|
+
info: {
|
|
50
|
+
menuIndex: 0
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
layout: (make, view) => {
|
|
54
|
+
make.center.equalTo(view.super);
|
|
55
|
+
make.size.equalTo($size(100, 100));
|
|
56
|
+
},
|
|
57
|
+
views: [{
|
|
58
|
+
type: "label",
|
|
59
|
+
props: {
|
|
60
|
+
text: "长按我",
|
|
61
|
+
textColor: $color("black"),
|
|
62
|
+
align: $align.center
|
|
63
|
+
},
|
|
64
|
+
layout: $layout.center
|
|
65
|
+
}]
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
$ui.render({
|
|
69
|
+
views: [view.definition]
|
|
70
|
+
})
|
|
@@ -49,7 +49,7 @@ const sections: PreferenceSection[] = [
|
|
|
49
49
|
value: 1,
|
|
50
50
|
decimal: 0,
|
|
51
51
|
min: 0,
|
|
52
|
-
max:
|
|
52
|
+
max: 2
|
|
53
53
|
},
|
|
54
54
|
{
|
|
55
55
|
type: "list",
|
|
@@ -64,6 +64,12 @@ const sections: PreferenceSection[] = [
|
|
|
64
64
|
key: "tab",
|
|
65
65
|
items: ["测试aaa", "测试bbb"],
|
|
66
66
|
value: 0
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: "date",
|
|
70
|
+
title: "date",
|
|
71
|
+
key: "date",
|
|
72
|
+
mode: 1
|
|
67
73
|
}
|
|
68
74
|
]
|
|
69
75
|
},
|
|
@@ -93,7 +99,10 @@ const v = new DynamicPreferenceListView({
|
|
|
93
99
|
sections: sections,
|
|
94
100
|
layout: $layout.fill,
|
|
95
101
|
events: {
|
|
96
|
-
changed: (values: any) =>
|
|
102
|
+
changed: (values: any) => {
|
|
103
|
+
console.info(values)
|
|
104
|
+
console.info(values.date)
|
|
105
|
+
}
|
|
97
106
|
}
|
|
98
107
|
});
|
|
99
108
|
|