iOS:add ListItem actions api
This commit is contained in:
parent
cc7df5d2ca
commit
e18b7e781e
@ -1,4 +1,4 @@
|
||||
import { Group, Panel, List, text, gravity, Color, LayoutSpec, list, listItem, log, vlayout, Gravity, hlayout, Text, refreshable, Refreshable, ListItem, layoutConfig, ViewHolder, ViewModel, VMPanel, loge } from "doric";
|
||||
import { Group, Panel, List, text, gravity, Color, LayoutSpec, list, listItem, log, vlayout, Gravity, hlayout, Text, refreshable, Refreshable, ListItem, layoutConfig, ViewHolder, ViewModel, VMPanel, loge, modal } from "doric";
|
||||
|
||||
interface ItemModel {
|
||||
text: string
|
||||
@ -80,6 +80,21 @@ class ListVM extends ViewModel<ListModel, ListVH> {
|
||||
widthSpec: LayoutSpec.MOST,
|
||||
heightSpec: LayoutSpec.FIT,
|
||||
}
|
||||
}).apply({
|
||||
actions: [
|
||||
{
|
||||
title: "First",
|
||||
callback: () => {
|
||||
modal(context).alert("First action")
|
||||
}
|
||||
},
|
||||
{
|
||||
title: "Second",
|
||||
callback: () => {
|
||||
modal(context).alert("Second action")
|
||||
}
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
onLoadMore: async () => {
|
||||
|
@ -34,4 +34,11 @@ - (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
self.reusable = YES;
|
||||
}
|
||||
|
||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"identifier" isEqualToString:name] || [@"actions" isEqualToString:name]) {
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
@ -18,11 +18,14 @@
|
||||
//
|
||||
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import <DoricCore/Doric.h>
|
||||
#import "DoricListNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricListItemNode.h"
|
||||
#import "DoricRefreshableNode.h"
|
||||
#import "DoricJSDispatcher.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricExtensions.h"
|
||||
|
||||
@interface DoricTableViewCell : UITableViewCell
|
||||
@property(nonatomic, strong) DoricListItemNode *doricListItemNode;
|
||||
@ -44,6 +47,7 @@ - (CGSize)sizeThatFits:(CGSize)size {
|
||||
@interface DoricListNode () <UITableViewDataSource, UITableViewDelegate>
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSNumber *> *itemHeights;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSArray *> *itemActions;
|
||||
@property(nonatomic, assign) NSUInteger itemCount;
|
||||
@property(nonatomic, assign) NSUInteger batchCount;
|
||||
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
|
||||
@ -62,6 +66,7 @@ - (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_itemViewIds = [NSMutableDictionary new];
|
||||
_itemHeights = [NSMutableDictionary new];
|
||||
_itemActions = [NSMutableDictionary new];
|
||||
_batchCount = 15;
|
||||
}
|
||||
return self;
|
||||
@ -144,6 +149,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
|
||||
NSDictionary *model = [self itemModelAt:position];
|
||||
NSDictionary *props = model[@"props"];
|
||||
NSString *reuseId = props[@"identifier"];
|
||||
self.itemActions[@(position)] = props[@"actions"];
|
||||
if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) {
|
||||
reuseId = @"doricLoadMoreCell";
|
||||
[self callLoadMore];
|
||||
@ -175,7 +181,53 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa
|
||||
} else {
|
||||
return 44.f;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray *actions = self.itemActions[@(indexPath.row)];
|
||||
return actions.count > 0;
|
||||
}
|
||||
|
||||
- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSArray *actions = self.itemActions[@(indexPath.row)];
|
||||
NSMutableArray <UITableViewRowAction *> *array = [NSMutableArray new];
|
||||
for (NSDictionary *action in actions) {
|
||||
__weak typeof(self) _self = self;
|
||||
UITableViewRowAction *tableViewRowAction = [UITableViewRowAction
|
||||
rowActionWithStyle:UITableViewRowActionStyleNormal
|
||||
title:action[@"title"]
|
||||
handler:^(UITableViewRowAction *tableViewRowAction, NSIndexPath *indexPath) {
|
||||
__strong typeof(_self) self = _self;
|
||||
[self callJSResponse:action[@"callback"], nil];
|
||||
}];
|
||||
[action[@"backgroundColor"] let:^(id it) {
|
||||
tableViewRowAction.backgroundColor = DoricColor(it);
|
||||
}];
|
||||
[array addObject:tableViewRowAction];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
- (nullable UISwipeActionsConfiguration *)tableView:(UITableView *)tableView trailingSwipeActionsConfigurationForRowAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(11.0)) {
|
||||
NSArray *actions = self.itemActions[@(indexPath.row)];
|
||||
NSMutableArray<UIContextualAction *> *array = [NSMutableArray new];
|
||||
for (NSDictionary *action in actions) {
|
||||
__weak typeof(self) _self = self;
|
||||
UIContextualAction *contextualAction = [UIContextualAction
|
||||
contextualActionWithStyle:UIContextualActionStyleNormal
|
||||
title:action[@"title"]
|
||||
handler:^(UIContextualAction *_Nonnull contextualAction, __kindof UIView *_Nonnull sourceView, void (^_Nonnull completionHandler)(BOOL)) {
|
||||
__strong typeof(_self) self = _self;
|
||||
[self callJSResponse:action[@"callback"], nil];
|
||||
}];
|
||||
[action[@"backgroundColor"] let:^(id it) {
|
||||
contextualAction.backgroundColor = DoricColor(it);
|
||||
}];
|
||||
[array addObject:contextualAction];
|
||||
}
|
||||
UISwipeActionsConfiguration *configuration = [UISwipeActionsConfiguration configurationWithActions:array];
|
||||
configuration.performsFirstActionWithFullSwipe = NO;
|
||||
return configuration;
|
||||
}
|
||||
|
||||
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
||||
|
@ -2,9 +2,12 @@
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function obj2Model(obj) {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(function (e) { return obj2Model(e); });
|
||||
function obj2Model(obj, convertor) {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj);
|
||||
}
|
||||
else if (obj instanceof Array) {
|
||||
return obj.map(function (e) { return obj2Model(e, convertor); });
|
||||
}
|
||||
else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
@ -14,7 +17,7 @@ function obj2Model(obj) {
|
||||
else {
|
||||
for (var key in obj) {
|
||||
var val = Reflect.get(obj, key);
|
||||
Reflect.set(obj, key, obj2Model(val));
|
||||
Reflect.set(obj, key, obj2Model(val, convertor));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -298,11 +301,12 @@ var View = /** @class */ (function () {
|
||||
configurable: true
|
||||
});
|
||||
View.prototype.onPropertyChanged = function (propKey, oldV, newV) {
|
||||
var _this = this;
|
||||
if (newV instanceof Function) {
|
||||
newV = this.callback2Id(newV);
|
||||
}
|
||||
else {
|
||||
newV = obj2Model(newV);
|
||||
newV = obj2Model(newV, function (v) { return _this.callback2Id(v); });
|
||||
}
|
||||
if (this.__dirty_props__ === undefined) {
|
||||
this.__dirty_props__ = {};
|
||||
@ -2048,6 +2052,10 @@ var ListItem = /** @class */ (function (_super) {
|
||||
Property,
|
||||
__metadata$8("design:type", String)
|
||||
], ListItem.prototype, "identifier", void 0);
|
||||
__decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", Array)
|
||||
], ListItem.prototype, "actions", void 0);
|
||||
return ListItem;
|
||||
}(Stack));
|
||||
var List = /** @class */ (function (_super) {
|
||||
|
@ -2,9 +2,12 @@
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function obj2Model(obj) {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e));
|
||||
function obj2Model(obj, convertor) {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj);
|
||||
}
|
||||
else if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e, convertor));
|
||||
}
|
||||
else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
@ -14,7 +17,7 @@ function obj2Model(obj) {
|
||||
else {
|
||||
for (let key in obj) {
|
||||
const val = Reflect.get(obj, key);
|
||||
Reflect.set(obj, key, obj2Model(val));
|
||||
Reflect.set(obj, key, obj2Model(val, convertor));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -228,7 +231,7 @@ class View {
|
||||
newV = this.callback2Id(newV);
|
||||
}
|
||||
else {
|
||||
newV = obj2Model(newV);
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v));
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV;
|
||||
}
|
||||
@ -1548,6 +1551,10 @@ __decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", String)
|
||||
], ListItem.prototype, "identifier", void 0);
|
||||
__decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", Array)
|
||||
], ListItem.prototype, "actions", void 0);
|
||||
class List extends Superview {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
@ -1593,9 +1593,12 @@ var doric = /*#__PURE__*/Object.freeze({
|
||||
jsCallbackTimer: jsCallbackTimer
|
||||
});
|
||||
|
||||
function obj2Model(obj) {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e));
|
||||
function obj2Model(obj, convertor) {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj);
|
||||
}
|
||||
else if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e, convertor));
|
||||
}
|
||||
else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
@ -1605,7 +1608,7 @@ function obj2Model(obj) {
|
||||
else {
|
||||
for (let key in obj) {
|
||||
const val = Reflect.get(obj, key);
|
||||
Reflect.set(obj, key, obj2Model(val));
|
||||
Reflect.set(obj, key, obj2Model(val, convertor));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -1749,7 +1752,7 @@ class View {
|
||||
newV = this.callback2Id(newV);
|
||||
}
|
||||
else {
|
||||
newV = obj2Model(newV);
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v));
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV;
|
||||
}
|
||||
@ -3069,6 +3072,10 @@ __decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", String)
|
||||
], ListItem.prototype, "identifier", void 0);
|
||||
__decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", Array)
|
||||
], ListItem.prototype, "actions", void 0);
|
||||
class List extends Superview {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
8
doric-js/index.d.ts
vendored
8
doric-js/index.d.ts
vendored
@ -587,11 +587,17 @@ declare module 'doric/lib/src/widget/list' {
|
||||
import { View, Superview, NativeViewModel } from "doric/lib/src/ui/view";
|
||||
import { Stack } from "doric/lib/src/widget/layouts";
|
||||
import { BridgeContext } from "doric/lib/src/runtime/global";
|
||||
import { Color } from "doric/lib/src/util/color";
|
||||
export class ListItem extends Stack {
|
||||
/**
|
||||
* Set to reuse native view
|
||||
*/
|
||||
identifier?: string;
|
||||
actions?: {
|
||||
title: string;
|
||||
backgroundColor?: Color;
|
||||
callback: () => void;
|
||||
}[];
|
||||
}
|
||||
export class List extends Superview {
|
||||
allSubviews(): IterableIterator<ListItem> | ListItem[];
|
||||
@ -1187,7 +1193,7 @@ declare module 'doric/lib/src/util/types' {
|
||||
export interface Modeling {
|
||||
toModel(): Model;
|
||||
}
|
||||
export function obj2Model(obj: Model): Model;
|
||||
export function obj2Model(obj: Model, convertor: (v: Function) => string): Model;
|
||||
type _M = string | number | boolean | Modeling | {
|
||||
[index: string]: Model;
|
||||
} | undefined;
|
||||
|
@ -113,7 +113,7 @@ export class View {
|
||||
newV = this.callback2Id(newV);
|
||||
}
|
||||
else {
|
||||
newV = obj2Model(newV);
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v));
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV;
|
||||
}
|
||||
|
2
doric-js/lib/src/util/types.d.ts
vendored
2
doric-js/lib/src/util/types.d.ts
vendored
@ -1,7 +1,7 @@
|
||||
export interface Modeling {
|
||||
toModel(): Model;
|
||||
}
|
||||
export declare function obj2Model(obj: Model): Model;
|
||||
export declare function obj2Model(obj: Model, convertor: (v: Function) => string): Model;
|
||||
declare type _M = string | number | boolean | Modeling | {
|
||||
[index: string]: Model;
|
||||
} | undefined;
|
||||
|
@ -1,6 +1,9 @@
|
||||
export function obj2Model(obj) {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e));
|
||||
export function obj2Model(obj, convertor) {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj);
|
||||
}
|
||||
else if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e, convertor));
|
||||
}
|
||||
else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
@ -10,7 +13,7 @@ export function obj2Model(obj) {
|
||||
else {
|
||||
for (let key in obj) {
|
||||
const val = Reflect.get(obj, key);
|
||||
Reflect.set(obj, key, obj2Model(val));
|
||||
Reflect.set(obj, key, obj2Model(val, convertor));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
6
doric-js/lib/src/widget/list.d.ts
vendored
6
doric-js/lib/src/widget/list.d.ts
vendored
@ -1,11 +1,17 @@
|
||||
import { View, Superview, NativeViewModel } from "../ui/view";
|
||||
import { Stack } from "./layouts";
|
||||
import { BridgeContext } from "../runtime/global";
|
||||
import { Color } from "../util/color";
|
||||
export declare class ListItem extends Stack {
|
||||
/**
|
||||
* Set to reuse native view
|
||||
*/
|
||||
identifier?: string;
|
||||
actions?: {
|
||||
title: string;
|
||||
backgroundColor?: Color;
|
||||
callback: () => void;
|
||||
}[];
|
||||
}
|
||||
export declare class List extends Superview {
|
||||
private cachedViews;
|
||||
|
@ -31,6 +31,10 @@ __decorate([
|
||||
Property,
|
||||
__metadata("design:type", String)
|
||||
], ListItem.prototype, "identifier", void 0);
|
||||
__decorate([
|
||||
Property,
|
||||
__metadata("design:type", Array)
|
||||
], ListItem.prototype, "actions", void 0);
|
||||
export class List extends Superview {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
@ -193,7 +193,7 @@ export abstract class View implements Modeling {
|
||||
if (newV instanceof Function) {
|
||||
newV = this.callback2Id(newV)
|
||||
} else {
|
||||
newV = obj2Model(newV)
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v))
|
||||
}
|
||||
if (this.__dirty_props__ === undefined) {
|
||||
this.__dirty_props__ = {}
|
||||
|
@ -199,7 +199,7 @@ export abstract class View implements Modeling {
|
||||
if (newV instanceof Function) {
|
||||
newV = this.callback2Id(newV)
|
||||
} else {
|
||||
newV = obj2Model(newV)
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v))
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV
|
||||
}
|
||||
|
@ -16,9 +16,11 @@
|
||||
export interface Modeling {
|
||||
toModel(): Model
|
||||
}
|
||||
export function obj2Model(obj: Model): Model {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e)) as Model
|
||||
export function obj2Model(obj: Model, convertor: (v: Function) => string): Model {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj)
|
||||
} else if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e, convertor)) as Model
|
||||
} else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
obj = Reflect.apply(Reflect.get(obj, 'toModel'), obj, [])
|
||||
@ -26,7 +28,7 @@ export function obj2Model(obj: Model): Model {
|
||||
} else {
|
||||
for (let key in obj) {
|
||||
const val = Reflect.get(obj, key)
|
||||
Reflect.set(obj, key, obj2Model(val))
|
||||
Reflect.set(obj, key, obj2Model(val, convertor))
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import { View, Property, Superview, NativeViewModel } from "../ui/view";
|
||||
import { Stack } from "./layouts";
|
||||
import { layoutConfig } from "../util/layoutconfig";
|
||||
import { BridgeContext } from "../runtime/global";
|
||||
|
||||
import { Color } from "../util/color";
|
||||
|
||||
export class ListItem extends Stack {
|
||||
/**
|
||||
@ -26,6 +26,13 @@ export class ListItem extends Stack {
|
||||
*/
|
||||
@Property
|
||||
identifier?: string
|
||||
|
||||
@Property
|
||||
actions?: {
|
||||
title: string,
|
||||
backgroundColor?: Color,
|
||||
callback: () => void,
|
||||
}[]
|
||||
}
|
||||
|
||||
export class List extends Superview {
|
||||
|
17
doric-web/dist/index.js
vendored
17
doric-web/dist/index.js
vendored
@ -1577,9 +1577,12 @@ Reflect.apply(doric.jsRegisterModule,this,["doric",Reflect.apply(function(__modu
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function obj2Model(obj) {
|
||||
if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e));
|
||||
function obj2Model(obj, convertor) {
|
||||
if (obj instanceof Function) {
|
||||
return convertor(obj);
|
||||
}
|
||||
else if (obj instanceof Array) {
|
||||
return obj.map(e => obj2Model(e, convertor));
|
||||
}
|
||||
else if (obj instanceof Object) {
|
||||
if (Reflect.has(obj, 'toModel') && Reflect.get(obj, 'toModel') instanceof Function) {
|
||||
@ -1589,7 +1592,7 @@ function obj2Model(obj) {
|
||||
else {
|
||||
for (let key in obj) {
|
||||
const val = Reflect.get(obj, key);
|
||||
Reflect.set(obj, key, obj2Model(val));
|
||||
Reflect.set(obj, key, obj2Model(val, convertor));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
@ -1803,7 +1806,7 @@ class View {
|
||||
newV = this.callback2Id(newV);
|
||||
}
|
||||
else {
|
||||
newV = obj2Model(newV);
|
||||
newV = obj2Model(newV, (v) => this.callback2Id(v));
|
||||
}
|
||||
this.__dirty_props__[propKey] = newV;
|
||||
}
|
||||
@ -3123,6 +3126,10 @@ __decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", String)
|
||||
], ListItem.prototype, "identifier", void 0);
|
||||
__decorate$8([
|
||||
Property,
|
||||
__metadata$8("design:type", Array)
|
||||
], ListItem.prototype, "actions", void 0);
|
||||
class List extends Superview {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
|
2
doric-web/dist/index.js.map
vendored
2
doric-web/dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user