rename dirs
This commit is contained in:
0
doric-iOS/Pod/Assets/.gitkeep
Normal file
0
doric-iOS/Pod/Assets/.gitkeep
Normal file
1
doric-iOS/Pod/Assets/bundle
Symbolic link
1
doric-iOS/Pod/Assets/bundle
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../js-framework/bundle
|
1
doric-iOS/Pod/Assets/dist
Symbolic link
1
doric-iOS/Pod/Assets/dist
Symbolic link
@@ -0,0 +1 @@
|
||||
../../../debugger/dist
|
0
doric-iOS/Pod/Classes/.gitkeep
Normal file
0
doric-iOS/Pod/Classes/.gitkeep
Normal file
31
doric-iOS/Pod/Classes/Dev/DoricLocalServer.h
Normal file
31
doric-iOS/Pod/Classes/Dev/DoricLocalServer.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricLocalServer.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/14.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricLocalServer : NSObject
|
||||
- (void)startWithPort:(NSUInteger)port;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
130
doric-iOS/Pod/Classes/Dev/DoricLocalServer.m
Normal file
130
doric-iOS/Pod/Classes/Dev/DoricLocalServer.m
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricLocalServer.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/14.
|
||||
//
|
||||
|
||||
#import "DoricLocalServer.h"
|
||||
#import "GCDWebServer.h"
|
||||
#import "GCDWebServerDataResponse.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricContextManager.h"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <net/if.h>
|
||||
#include <ifaddrs.h>
|
||||
|
||||
typedef id (^ServerHandler)(GCDWebServerRequest *request);
|
||||
|
||||
@interface DoricLocalServer ()
|
||||
@property(nonatomic, strong) GCDWebServer *server;
|
||||
@property(nonatomic, strong) NSMutableDictionary *handlers;
|
||||
@end
|
||||
|
||||
@implementation DoricLocalServer
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_server = [[GCDWebServer alloc] init];
|
||||
_handlers = [[NSMutableDictionary alloc] init];
|
||||
[self configurate];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSString *)localIPAddress {
|
||||
NSString *localIP = nil;
|
||||
struct ifaddrs *addrs;
|
||||
if (getifaddrs(&addrs) == 0) {
|
||||
const struct ifaddrs *cursor = addrs;
|
||||
while (cursor != NULL) {
|
||||
if (cursor->ifa_addr->sa_family == AF_INET && (cursor->ifa_flags & IFF_LOOPBACK) == 0) {
|
||||
//NSString *name = [NSString stringWithUTF8String:cursor->ifa_name];
|
||||
//if ([name isEqualToString:@"en0"]) // Wi-Fi adapter
|
||||
{
|
||||
localIP = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *) cursor->ifa_addr)->sin_addr)];
|
||||
break;
|
||||
}
|
||||
}
|
||||
cursor = cursor->ifa_next;
|
||||
}
|
||||
freeifaddrs(addrs);
|
||||
}
|
||||
return localIP;
|
||||
}
|
||||
|
||||
- (GCDWebServerResponse *)handleRequest:(GCDWebServerRequest *)request {
|
||||
if ([request.path hasPrefix:@"/api/"]) {
|
||||
NSString *command = [request.path substringFromIndex:@"/api/".length];
|
||||
ServerHandler handler = [self.handlers objectForKey:command];
|
||||
if (handler) {
|
||||
id dic = handler(request);
|
||||
return [GCDWebServerDataResponse responseWithJSONObject:dic];
|
||||
}
|
||||
return [GCDWebServerDataResponse responseWithHTML:@"<html><body><p>It's a API request.</p></body></html>"];
|
||||
}
|
||||
NSBundle *bundle = DoricBundle();
|
||||
NSString *filePath = [NSString stringWithFormat:@"%@/dist%@", bundle.bundlePath, request.path];
|
||||
NSData *data = [NSData dataWithContentsOfFile:filePath];
|
||||
NSURL *url = [NSURL fileURLWithPath:filePath];
|
||||
NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:url];
|
||||
NSHTTPURLResponse *response;
|
||||
[NSURLConnection sendSynchronousRequest:req returningResponse:&response error:nil];
|
||||
return [GCDWebServerDataResponse responseWithData:data contentType:response.MIMEType];
|
||||
}
|
||||
|
||||
- (void)configurate {
|
||||
__weak typeof(self) _self = self;
|
||||
[self.server addDefaultHandlerForMethod:@"GET"
|
||||
requestClass:[GCDWebServerRequest class]
|
||||
processBlock:^GCDWebServerResponse *(GCDWebServerRequest *request) {
|
||||
__strong typeof(_self) self = _self;
|
||||
return [self handleRequest:request];
|
||||
}];
|
||||
[self.handlers setObject:^id(GCDWebServerRequest *request) {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
|
||||
for (NSValue *value in [[DoricContextManager instance] aliveContexts]) {
|
||||
DoricContext *context = value.nonretainedObjectValue;
|
||||
[array addObject:@{
|
||||
@"source": context.source,
|
||||
@"id": context.contextId,
|
||||
}];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
forKey:@"allContexts"];
|
||||
|
||||
[self.handlers setObject:^id(GCDWebServerRequest *request) {
|
||||
NSString *contextId = [request.query objectForKey:@"id"];
|
||||
DoricContext *context = [[DoricContextManager instance] getContext:contextId];
|
||||
return @{
|
||||
@"id": context.contextId,
|
||||
@"source": context.source,
|
||||
@"script": context.script
|
||||
};
|
||||
}
|
||||
forKey:@"context"];
|
||||
}
|
||||
|
||||
- (void)startWithPort:(NSUInteger)port {
|
||||
[self.server startWithPort:port bonjourName:nil];
|
||||
DoricLog(@"Start Server At %@:%d", [self localIPAddress], port);
|
||||
}
|
||||
@end
|
33
doric-iOS/Pod/Classes/Dev/DoricWSClient.h
Normal file
33
doric-iOS/Pod/Classes/Dev/DoricWSClient.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// WSClient.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/14.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricWSClient : NSObject
|
||||
- (instancetype)initWithUrl:(NSString *)url;
|
||||
|
||||
- (void)close;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
81
doric-iOS/Pod/Classes/Dev/DoricWSClient.m
Normal file
81
doric-iOS/Pod/Classes/Dev/DoricWSClient.m
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// WSClient.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/14.
|
||||
//
|
||||
|
||||
#import "DoricWSClient.h"
|
||||
#import <SocketRocket/SRWebSocket.h>
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricContextManager.h"
|
||||
|
||||
@interface DoricWSClient () <SRWebSocketDelegate>
|
||||
@property(nonatomic, strong) SRWebSocket *websocket;
|
||||
@end
|
||||
|
||||
@implementation DoricWSClient
|
||||
- (instancetype)initWithUrl:(NSString *)url {
|
||||
if (self = [super init]) {
|
||||
_websocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:url]];
|
||||
_websocket.delegate = self;
|
||||
[_websocket open];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
|
||||
DoricLog(@"webSocketDidOpen");
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
|
||||
DoricLog(@"webSocketdidReceivePong");
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
|
||||
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *err;
|
||||
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&err];
|
||||
if (err) {
|
||||
DoricLog(@"webSocketdidReceiveMessage parse error:%@", err);
|
||||
return;
|
||||
}
|
||||
NSString *source = [[dic valueForKey:@"source"] mutableCopy];
|
||||
NSString *script = [dic valueForKey:@"script"];
|
||||
for (NSValue *value in [[DoricContextManager instance] aliveContexts]) {
|
||||
DoricContext *context = value.nonretainedObjectValue;
|
||||
if ([source containsString:context.source]) {
|
||||
[context reload:script];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
|
||||
DoricLog(@"webSocketdidFailWithError");
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
|
||||
DoricLog(@"webSocketdidCloseWithCode");
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self.websocket close];
|
||||
}
|
||||
@end
|
28
doric-iOS/Pod/Classes/Doric.h
Normal file
28
doric-iOS/Pod/Classes/Doric.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#import "DoricContext.h"
|
||||
#import "DoricLayouts.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricViewNode.h"
|
||||
#import "DoricRootNode.h"
|
||||
#import "UIView+Doric.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricPanel.h"
|
||||
#import "DoricJSLoaderManager.h"
|
||||
#import "DoricNavigatorDelegate.h"
|
||||
#import "DoricNavBarDelegate.h"
|
||||
#import "DoricViewController.h"
|
||||
#import "DoricPromise.h"
|
64
doric-iOS/Pod/Classes/DoricContext.h
Normal file
64
doric-iOS/Pod/Classes/DoricContext.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricContext.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricDriver.h"
|
||||
#import "DoricNavigatorDelegate.h"
|
||||
#import "DoricNavBarDelegate.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class DoricViewNode;
|
||||
@class DoricRootNode;
|
||||
|
||||
@interface DoricContext : NSObject
|
||||
@property(nonatomic, weak) id <DoricNavigatorDelegate> navigator;
|
||||
@property(nonatomic, weak) id <DoricNavBarDelegate> navBar;
|
||||
@property(nonatomic, strong) NSString *contextId;
|
||||
@property(nonatomic, strong) DoricDriver *driver;
|
||||
@property(nonatomic, strong) NSMutableDictionary *pluginInstanceMap;
|
||||
@property(nonatomic, strong) NSString *source;
|
||||
@property(nonatomic, strong) NSString *script;;
|
||||
@property(nonatomic, strong) NSMutableDictionary *initialParams;
|
||||
@property(nonatomic, strong) DoricRootNode *rootNode;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSString *, DoricViewNode *> *headNodes;
|
||||
|
||||
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source;
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method, ...;
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method withArguments:(va_list)args;
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method withArgumentsArray:(NSArray *)args;
|
||||
|
||||
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height;
|
||||
|
||||
- (void)reload:(NSString *)script;
|
||||
|
||||
- (void)onShow;
|
||||
|
||||
- (void)onHidden;
|
||||
|
||||
- (DoricViewNode *)targetViewNode:(NSString *)viewId;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
99
doric-iOS/Pod/Classes/DoricContext.m
Normal file
99
doric-iOS/Pod/Classes/DoricContext.m
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricContext.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
//
|
||||
|
||||
#import "DoricContext.h"
|
||||
#import "DoricContextManager.h"
|
||||
#import "DoricRootNode.h"
|
||||
#import "DoricConstant.h"
|
||||
#import "DoricExtensions.h"
|
||||
|
||||
@implementation DoricContext
|
||||
|
||||
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source {
|
||||
if (self = [super init]) {
|
||||
_driver = [DoricDriver instance];
|
||||
_pluginInstanceMap = [NSMutableDictionary new];
|
||||
[[DoricContextManager instance] createContext:self script:script source:source];
|
||||
_headNodes = [NSMutableDictionary new];
|
||||
DoricRootNode *rootNode = [[DoricRootNode alloc] initWithContext:self];
|
||||
_rootNode = rootNode;
|
||||
_script = script;
|
||||
_source = source;
|
||||
_initialParams = [@{@"width": @(0), @"height": @(0)} mutableCopy];
|
||||
[self callEntity:DORIC_ENTITY_CREATE, nil];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (DoricViewNode *)targetViewNode:(NSString *)viewId {
|
||||
if ([self.rootNode.viewId isEqualToString:viewId]) {
|
||||
return self.rootNode;
|
||||
} else {
|
||||
return self.headNodes[viewId];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self callEntity:DORIC_ENTITY_DESTROY, nil];
|
||||
[[DoricContextManager instance] destroyContext:self];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method, ... {
|
||||
va_list args;
|
||||
va_start(args, method);
|
||||
DoricAsyncResult *ret = [self.driver invokeContextEntity:self.contextId method:method arguments:args];
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method withArguments:(va_list)args {
|
||||
return [self.driver invokeContextEntity:self.contextId method:method arguments:args];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)callEntity:(NSString *)method withArgumentsArray:(NSArray *)args {
|
||||
return [self.driver invokeContextEntity:self.contextId method:method argumentsArray:args];
|
||||
}
|
||||
|
||||
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
|
||||
[self.initialParams also:^(NSMutableDictionary *it) {
|
||||
it[@"width"] = @(width);
|
||||
it[@"height"] = @(height);
|
||||
}];
|
||||
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
||||
}
|
||||
|
||||
- (void)reload:(NSString *)script {
|
||||
self.rootNode.viewId = nil;
|
||||
self.script = script;
|
||||
[self.driver createContext:self.contextId script:script source:self.source];
|
||||
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
|
||||
}
|
||||
|
||||
- (void)onShow {
|
||||
[self callEntity:DORIC_ENTITY_SHOW, nil];
|
||||
}
|
||||
|
||||
- (void)onHidden {
|
||||
[self callEntity:DORIC_ENTITY_HIDDEN, nil];
|
||||
}
|
||||
|
||||
@end
|
35
doric-iOS/Pod/Classes/DoricContextHolder.h
Normal file
35
doric-iOS/Pod/Classes/DoricContextHolder.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricComponent.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricContext.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricContextHolder : NSObject
|
||||
@property(nonatomic, strong) DoricContext *doricContext;
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
34
doric-iOS/Pod/Classes/DoricContextHolder.m
Normal file
34
doric-iOS/Pod/Classes/DoricContextHolder.m
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricComponent.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricContextHolder.h"
|
||||
|
||||
@implementation DoricContextHolder
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [self init]) {
|
||||
_doricContext = doricContext;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
40
doric-iOS/Pod/Classes/DoricContextManager.h
Normal file
40
doric-iOS/Pod/Classes/DoricContextManager.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricContextManager.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricContext.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricContextManager : NSObject
|
||||
+ (instancetype)instance;
|
||||
|
||||
- (void)createContext:(DoricContext *)context script:(NSString *)script source:(NSString *)source;
|
||||
|
||||
- (void)destroyContext:(DoricContext *)context;
|
||||
|
||||
- (DoricContext *)getContext:(NSString *)contextId;
|
||||
|
||||
- (NSArray *)aliveContexts;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
84
doric-iOS/Pod/Classes/DoricContextManager.m
Normal file
84
doric-iOS/Pod/Classes/DoricContextManager.m
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricContextManager.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricContextManager.h"
|
||||
#import "DoricContext.h"
|
||||
|
||||
@interface DoricContextManager ()
|
||||
|
||||
@property(nonatomic) NSInteger counter;
|
||||
@property(nonatomic, strong) NSMutableDictionary *doricContextMap;
|
||||
@property(nonatomic, strong) dispatch_queue_t mapQueue;
|
||||
@end
|
||||
|
||||
@implementation DoricContextManager
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_doricContextMap = [[NSMutableDictionary alloc] init];
|
||||
_counter = 0;
|
||||
_mapQueue = dispatch_queue_create("doric.contextmap", DISPATCH_QUEUE_SERIAL);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (instancetype)instance {
|
||||
static DoricContextManager *_instance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_instance = [[DoricContextManager alloc] init];
|
||||
});
|
||||
return _instance;
|
||||
}
|
||||
|
||||
- (void)createContext:(DoricContext *)context script:(NSString *)script source:(NSString *)source {
|
||||
context.contextId = [NSString stringWithFormat:@"%ld", (long) ++self.counter];
|
||||
[context.driver createContext:context.contextId script:script source:source];
|
||||
dispatch_sync(self.mapQueue, ^() {
|
||||
NSValue *value = [NSValue valueWithNonretainedObject:context];
|
||||
[self.doricContextMap setValue:value forKey:context.contextId];
|
||||
});
|
||||
}
|
||||
|
||||
- (DoricContext *)getContext:(NSString *)contextId {
|
||||
__block DoricContext *context;
|
||||
dispatch_sync(self.mapQueue, ^{
|
||||
NSValue *value = [self.doricContextMap valueForKey:contextId];
|
||||
context = value.nonretainedObjectValue;
|
||||
});
|
||||
return context;
|
||||
}
|
||||
|
||||
- (void)destroyContext:(DoricContext *)context {
|
||||
NSString *contextId = context.contextId;
|
||||
[context.driver destroyContext:contextId].finishCallback = ^{
|
||||
dispatch_sync(self.mapQueue, ^() {
|
||||
[self.doricContextMap removeObjectForKey:contextId];
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
- (NSArray *)aliveContexts {
|
||||
return [self.doricContextMap allValues];
|
||||
}
|
||||
|
||||
@end
|
59
doric-iOS/Pod/Classes/DoricDriver.h
Normal file
59
doric-iOS/Pod/Classes/DoricDriver.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricDriver.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricAsyncResult.h"
|
||||
#import "DoricRegistry.h"
|
||||
|
||||
typedef NS_ENUM(NSInteger, QueueMode) {
|
||||
JS = 0,
|
||||
UI,
|
||||
INDEPENDENT
|
||||
};
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricDriver : NSObject
|
||||
+ (instancetype)instance;
|
||||
|
||||
@property(nonatomic, strong) DoricRegistry *registry;
|
||||
|
||||
- (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source;
|
||||
|
||||
- (DoricAsyncResult *)destroyContext:(NSString *)contextId;
|
||||
|
||||
- (DoricAsyncResult *)invokeDoricMethod:(NSString *)method, ...;
|
||||
|
||||
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method, ...;
|
||||
|
||||
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method arguments:(va_list)args;
|
||||
|
||||
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method argumentsArray:(NSArray *)args;
|
||||
|
||||
- (void)connectDevKit:(NSString *)url;
|
||||
|
||||
- (void)disconnectDevKit;
|
||||
|
||||
- (void)ensureSyncInMainQueue:(dispatch_block_t)block;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
193
doric-iOS/Pod/Classes/DoricDriver.m
Normal file
193
doric-iOS/Pod/Classes/DoricDriver.m
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricDriver.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/26.
|
||||
//
|
||||
|
||||
#import "DoricDriver.h"
|
||||
#import "DoricJSEngine.h"
|
||||
#import "DoricConstant.h"
|
||||
#import "DoricWSClient.h"
|
||||
|
||||
@interface DoricDriver ()
|
||||
@property(nonatomic, strong) DoricJSEngine *jsExecutor;
|
||||
@property(nonatomic, strong) DoricWSClient *wsclient;
|
||||
@end
|
||||
|
||||
@implementation DoricDriver
|
||||
|
||||
@dynamic registry;
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_jsExecutor = [[DoricJSEngine alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (DoricRegistry *)registry {
|
||||
return self.jsExecutor.registry;
|
||||
}
|
||||
|
||||
+ (instancetype)instance {
|
||||
static DoricDriver *_instance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_instance = [[DoricDriver alloc] init];
|
||||
});
|
||||
return _instance;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult<JSValue *> *)invokeDoricMethod:(NSString *)method, ... {
|
||||
va_list args;
|
||||
va_start(args, method);
|
||||
DoricAsyncResult *ret = [self invokeDoricMethod:method arguments:args];
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult<JSValue *> *)invokeDoricMethod:(NSString *)method arguments:(va_list)args {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
id arg;
|
||||
while ((arg = va_arg(args, id)) != nil) {
|
||||
[array addObject:arg];
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsExecutor.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:method argumentsArray:array];
|
||||
[ret setupResult:jsValue];
|
||||
} @catch (NSException *exception) {
|
||||
[ret setupError:exception];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult<JSValue *> *)invokeContextEntity:(NSString *)contextId method:(NSString *)method, ... {
|
||||
va_list args;
|
||||
va_start(args, method);
|
||||
DoricAsyncResult *ret = [self invokeContextEntity:contextId method:method arguments:args];
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method arguments:(va_list)args {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:contextId];
|
||||
[array addObject:method];
|
||||
id arg = va_arg(args, id);
|
||||
while (arg != nil) {
|
||||
[array addObject:arg];
|
||||
arg = va_arg(args, JSValue *);
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsExecutor.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:DORIC_CONTEXT_INVOKE argumentsArray:array];
|
||||
[ret setupResult:jsValue];
|
||||
} @catch (NSException *exception) {
|
||||
[ret setupError:exception];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method argumentsArray:(NSArray *)args {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:contextId];
|
||||
[array addObject:method];
|
||||
for (id arg in args) {
|
||||
[array addObject:arg];
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsExecutor.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:DORIC_CONTEXT_INVOKE argumentsArray:array];
|
||||
[ret setupResult:jsValue];
|
||||
} @catch (NSException *exception) {
|
||||
[ret setupError:exception];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsExecutor.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
[self.jsExecutor prepareContext:contextId script:script source:source];
|
||||
[ret setupResult:[NSNumber numberWithBool:YES]];
|
||||
} @catch (NSException *exception) {
|
||||
[ret setupError:exception];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)destroyContext:(NSString *)contextId {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsExecutor.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
[self.jsExecutor destroyContext:contextId];
|
||||
[ret setupResult:[NSNumber numberWithBool:YES]];
|
||||
} @catch (NSException *exception) {
|
||||
[ret setupError:exception];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)connectDevKit:(NSString *)url {
|
||||
if (self.wsclient) {
|
||||
[self.wsclient close];
|
||||
}
|
||||
self.wsclient = [[DoricWSClient alloc] initWithUrl:url];
|
||||
}
|
||||
|
||||
- (void)disconnectDevKit {
|
||||
if (self.wsclient) {
|
||||
[self.wsclient close];
|
||||
self.wsclient = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ensureSyncInMainQueue:(dispatch_block_t)block {
|
||||
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {
|
||||
block();
|
||||
} else {
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
@end
|
29
doric-iOS/Pod/Classes/DoricPanel.h
Normal file
29
doric-iOS/Pod/Classes/DoricPanel.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricContext.h"
|
||||
#import "DoricNavigatorDelegate.h"
|
||||
|
||||
@interface DoricPanel : UIViewController
|
||||
@property(nonatomic, strong) DoricContext *doricContext;
|
||||
|
||||
- (void)config:(NSString *)script alias:(NSString *)alias;
|
||||
@end
|
54
doric-iOS/Pod/Classes/DoricPanel.m
Normal file
54
doric-iOS/Pod/Classes/DoricPanel.m
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricPanel.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@implementation DoricPanel
|
||||
|
||||
- (void)config:(NSString *)script alias:(NSString *)alias {
|
||||
self.doricContext = [[[DoricContext alloc] initWithScript:script source:alias] also:^(DoricContext *it) {
|
||||
[it.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {
|
||||
[self.view addSubview:it];
|
||||
}]];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
[self.doricContext.rootNode.view also:^(DoricStackView *it) {
|
||||
if (it.width != self.view.width || it.height != self.view.height) {
|
||||
it.width = self.view.width;
|
||||
it.height = self.view.height;
|
||||
[self.doricContext initContextWithWidth:it.width height:it.height];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated {
|
||||
[super viewDidAppear:animated];
|
||||
[self.doricContext onShow];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated {
|
||||
[super viewDidDisappear:animated];
|
||||
[self.doricContext onHidden];
|
||||
}
|
||||
|
||||
@end
|
43
doric-iOS/Pod/Classes/DoricRegistry.h
Normal file
43
doric-iOS/Pod/Classes/DoricRegistry.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricRegistry.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/27.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricRegistry : NSObject
|
||||
|
||||
- (NSString *)acquireJSBundle:(NSString *)name;
|
||||
|
||||
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name;
|
||||
|
||||
|
||||
- (void)registerNativePlugin:(Class)pluginClass withName:(NSString *)name;
|
||||
|
||||
- (Class)acquireNativePlugin:(NSString *)name;
|
||||
|
||||
- (void)registerViewNode:(Class)nodeClass withName:(NSString *)name;
|
||||
|
||||
- (Class)acquireViewNode:(NSString *)name;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
115
doric-iOS/Pod/Classes/DoricRegistry.m
Normal file
115
doric-iOS/Pod/Classes/DoricRegistry.m
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricRegistry.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/27.
|
||||
//
|
||||
|
||||
#import "DoricRegistry.h"
|
||||
#import "DoricModalPlugin.h"
|
||||
#import "DoricNetworkPlugin.h"
|
||||
#import "DoricShaderPlugin.h"
|
||||
#import "DoricStackNode.h"
|
||||
#import "DoricVLayoutNode.h"
|
||||
#import "DoricHLayoutNode.h"
|
||||
#import "DoricTextNode.h"
|
||||
#import "DoricImageNode.h"
|
||||
#import "DoricListNode.h"
|
||||
#import "DoricListItemNode.h"
|
||||
#import "DoricScrollerNode.h"
|
||||
#import "DoricSliderNode.h"
|
||||
#import "DoricSlideItemNode.h"
|
||||
#import "DoricStoragePlugin.h"
|
||||
#import "DoricNavigatorPlugin.h"
|
||||
#import "DoricNavBarPlugin.h"
|
||||
#import "DoricRefreshableNode.h"
|
||||
#import "DoricFlowLayoutItemNode.h"
|
||||
#import "DoricFlowLayoutNode.h"
|
||||
#import "DoricPopoverPlugin.h"
|
||||
#import "DoricAnimatePlugin.h"
|
||||
|
||||
@interface DoricRegistry ()
|
||||
|
||||
@property(nonatomic, strong) NSMutableDictionary *bundles;
|
||||
@property(nonatomic, strong) NSMutableDictionary *plugins;
|
||||
@property(nonatomic, strong) NSMutableDictionary *nodes;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricRegistry
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_bundles = [[NSMutableDictionary alloc] init];
|
||||
_plugins = [[NSMutableDictionary alloc] init];
|
||||
_nodes = [[NSMutableDictionary alloc] init];
|
||||
[self innerRegister];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)innerRegister {
|
||||
[self registerNativePlugin:DoricShaderPlugin.class withName:@"shader"];
|
||||
[self registerNativePlugin:DoricModalPlugin.class withName:@"modal"];
|
||||
[self registerNativePlugin:DoricNetworkPlugin.class withName:@"network"];
|
||||
[self registerNativePlugin:DoricStoragePlugin.class withName:@"storage"];
|
||||
[self registerNativePlugin:DoricNavigatorPlugin.class withName:@"navigator"];
|
||||
[self registerNativePlugin:DoricNavBarPlugin.class withName:@"navbar"];
|
||||
[self registerNativePlugin:DoricPopoverPlugin.class withName:@"popover"];
|
||||
[self registerNativePlugin:DoricAnimatePlugin.class withName:@"animate"];
|
||||
|
||||
[self registerViewNode:DoricStackNode.class withName:@"Stack"];
|
||||
[self registerViewNode:DoricVLayoutNode.class withName:@"VLayout"];
|
||||
[self registerViewNode:DoricHLayoutNode.class withName:@"HLayout"];
|
||||
[self registerViewNode:DoricTextNode.class withName:@"Text"];
|
||||
[self registerViewNode:DoricImageNode.class withName:@"Image"];
|
||||
[self registerViewNode:DoricListNode.class withName:@"List"];
|
||||
[self registerViewNode:DoricListItemNode.class withName:@"ListItem"];
|
||||
[self registerViewNode:DoricScrollerNode.class withName:@"Scroller"];
|
||||
[self registerViewNode:DoricSliderNode.class withName:@"Slider"];
|
||||
[self registerViewNode:DoricSlideItemNode.class withName:@"SlideItem"];
|
||||
[self registerViewNode:DoricRefreshableNode.class withName:@"Refreshable"];
|
||||
[self registerViewNode:DoricFlowLayoutItemNode.class withName:@"FlowLayoutItem"];
|
||||
[self registerViewNode:DoricFlowLayoutNode.class withName:@"FlowLayout"];
|
||||
}
|
||||
|
||||
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name {
|
||||
self.bundles[name] = bundle;
|
||||
}
|
||||
|
||||
- (NSString *)acquireJSBundle:(NSString *)name {
|
||||
return self.bundles[name];
|
||||
}
|
||||
|
||||
- (void)registerNativePlugin:(Class)pluginClass withName:(NSString *)name {
|
||||
self.plugins[name] = pluginClass;
|
||||
}
|
||||
|
||||
- (Class)acquireNativePlugin:(NSString *)name {
|
||||
return self.plugins[name];
|
||||
}
|
||||
|
||||
- (void)registerViewNode:(Class)nodeClass withName:(NSString *)name {
|
||||
self.nodes[name] = nodeClass;
|
||||
}
|
||||
|
||||
- (Class)acquireViewNode:(NSString *)name {
|
||||
return self.nodes[name];
|
||||
}
|
||||
|
||||
@end
|
26
doric-iOS/Pod/Classes/DoricViewController.h
Normal file
26
doric-iOS/Pod/Classes/DoricViewController.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNavigatorDelegate.h"
|
||||
#import "DoricNavBarDelegate.h"
|
||||
|
||||
@interface DoricViewController : UIViewController <DoricNavigatorDelegate, DoricNavBarDelegate>
|
||||
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias;
|
||||
@end
|
107
doric-iOS/Pod/Classes/DoricViewController.m
Normal file
107
doric-iOS/Pod/Classes/DoricViewController.m
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricViewController.h"
|
||||
#import "DoricAsyncResult.h"
|
||||
#import "DoricJSLoaderManager.h"
|
||||
#import "DoricPanel.h"
|
||||
#import "UIView+Doric.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
@interface DoricViewController ()
|
||||
@property(nonatomic, strong) DoricPanel *doricPanel;
|
||||
@property(nonatomic) BOOL navBarHidden;
|
||||
@property(nonatomic, strong) UIImage *navBarImage;
|
||||
@end
|
||||
|
||||
@implementation DoricViewController
|
||||
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias {
|
||||
if (self = [super init]) {
|
||||
self.edgesForExtendedLayout = UIRectEdgeNone;
|
||||
DoricAsyncResult <NSString *> *result = [DoricJSLoaderManager.instance request:scheme];
|
||||
result.resultCallback = ^(NSString *result) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
DoricPanel *panel = [DoricPanel new];
|
||||
[panel.view also:^(UIView *it) {
|
||||
it.backgroundColor = [UIColor whiteColor];
|
||||
it.width = self.view.width;
|
||||
it.height = self.view.height;
|
||||
}];
|
||||
[self.view addSubview:panel.view];
|
||||
[self addChildViewController:panel];
|
||||
[panel config:result alias:alias];
|
||||
panel.doricContext.navigator = self;
|
||||
panel.doricContext.navBar = self;
|
||||
self.doricPanel = panel;
|
||||
});
|
||||
};
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
self.navBarHidden = self.navigationController.navigationBarHidden;
|
||||
self.navBarImage = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
if (self.navigationController.navigationBarHidden != self.navBarHidden) {
|
||||
[self.navigationController setNavigationBarHidden:self.navBarHidden];
|
||||
}
|
||||
if (self.navBarImage != [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]) {
|
||||
[self.navigationController.navigationBar setBackgroundImage:self.navBarImage forBarMetrics:UIBarMetricsDefault];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillLayoutSubviews {
|
||||
[super viewWillLayoutSubviews];
|
||||
self.doricPanel.view.width = self.view.width;
|
||||
self.doricPanel.view.height = self.view.height;
|
||||
}
|
||||
|
||||
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated {
|
||||
DoricViewController *viewController = [[DoricViewController alloc] initWithScheme:scheme alias:alias];
|
||||
[self.navigationController pushViewController:viewController animated:animated];
|
||||
}
|
||||
|
||||
- (void)doric_navigator_pop:(BOOL)animated {
|
||||
[self.navigationController popViewControllerAnimated:animated];
|
||||
}
|
||||
|
||||
- (BOOL)doric_navBar_isHidden {
|
||||
return self.navigationController.navigationBarHidden;
|
||||
}
|
||||
|
||||
- (void)doric_navBar_setHidden:(BOOL)hidden {
|
||||
[self.navigationController setNavigationBarHidden:hidden];
|
||||
}
|
||||
|
||||
- (void)doric_navBar_setTitle:(NSString *)title {
|
||||
self.title = title;
|
||||
}
|
||||
|
||||
- (void)doric_navBar_setBackgroundColor:(UIColor *)color {
|
||||
[self.navigationController.navigationBar setBackgroundImage:UIImageWithColor(color) forBarMetrics:UIBarMetricsDefault];
|
||||
}
|
||||
|
||||
|
||||
@end
|
32
doric-iOS/Pod/Classes/Engine/DoricJSCoreExecutor.h
Normal file
32
doric-iOS/Pod/Classes/Engine/DoricJSCoreExecutor.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSCoreExecutor.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricJSExecutorProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricJSCoreExecutor : NSObject <DoricJSExecutorProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
64
doric-iOS/Pod/Classes/Engine/DoricJSCoreExecutor.m
Normal file
64
doric-iOS/Pod/Classes/Engine/DoricJSCoreExecutor.m
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSCoreExecutor.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
//
|
||||
|
||||
#import "DoricJSCoreExecutor.h"
|
||||
|
||||
@interface DoricJSCoreExecutor ()
|
||||
|
||||
@property(nonatomic, strong) JSContext *jsContext;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricJSCoreExecutor
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_jsContext = [[JSContext alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)checkJSException {
|
||||
if (self.jsContext.exception) {
|
||||
NSString *errMsg = [NSString stringWithFormat:@"%@ (line %@ in the generated bundle)\n/***StackTrace***/\n%@/***StackTrace***/", self.jsContext.exception, self.jsContext.exception[@"line"], self.jsContext.exception[@"stack"]];
|
||||
@throw [[NSException alloc] initWithName:@"DoricJS" reason:errMsg userInfo:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source {
|
||||
NSString *ret = [[self.jsContext evaluateScript:script withSourceURL:[NSURL URLWithString:source]] toString];
|
||||
[self checkJSException];
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj {
|
||||
self.jsContext[name] = obj;
|
||||
[self checkJSException];
|
||||
}
|
||||
|
||||
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args {
|
||||
JSValue *obj = [self.jsContext objectForKeyedSubscript:objName];
|
||||
JSValue *ret = [obj invokeMethod:funcName withArguments:args];
|
||||
[self checkJSException];
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
46
doric-iOS/Pod/Classes/Engine/DoricJSEngine.h
Normal file
46
doric-iOS/Pod/Classes/Engine/DoricJSEngine.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSEngine.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import "DoricRegistry.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricJSEngine : NSObject
|
||||
|
||||
@property(nonatomic, strong) dispatch_queue_t jsQueue;
|
||||
|
||||
@property(nonatomic, strong) DoricRegistry *registry;
|
||||
|
||||
- (void)prepareContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source;
|
||||
|
||||
- (void)destroyContext:(NSString *)contextId;
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method, ...;
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method arguments:(va_list)args;
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArray *)args;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
181
doric-iOS/Pod/Classes/Engine/DoricJSEngine.m
Normal file
181
doric-iOS/Pod/Classes/Engine/DoricJSEngine.m
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSEngine.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/26.
|
||||
//
|
||||
|
||||
#import "DoricJSEngine.h"
|
||||
#import "DoricJSExecutorProtocol.h"
|
||||
#import "DoricJSCoreExecutor.h"
|
||||
#import "DoricJSRemoteExecutor.h"
|
||||
#import "DoricConstant.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricBridgeExtension.h"
|
||||
|
||||
@interface DoricJSEngine ()
|
||||
@property(nonatomic, strong) id <DoricJSExecutorProtocol> jsExecutor;
|
||||
@property(nonatomic, strong) NSMutableDictionary *timers;
|
||||
@property(nonatomic, strong) DoricBridgeExtension *bridgeExtension;
|
||||
@end
|
||||
|
||||
@implementation DoricJSEngine
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_jsQueue = dispatch_queue_create("doric.jsengine", DISPATCH_QUEUE_SERIAL);
|
||||
_bridgeExtension = [[DoricBridgeExtension alloc] init];
|
||||
dispatch_async(_jsQueue, ^() {
|
||||
self.timers = [[NSMutableDictionary alloc] init];
|
||||
// Debug: 切换
|
||||
// self.jsExecutor = [[DoricJSRemoteExecutor alloc] init];
|
||||
self.jsExecutor = [DoricJSCoreExecutor new];
|
||||
self.registry = [[DoricRegistry alloc] init];
|
||||
[self initJSExecutor];
|
||||
[self initDoricEnvironment];
|
||||
});
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initJSExecutor {
|
||||
__weak typeof(self) _self = self;
|
||||
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_LOG obj:^(NSString *type, NSString *message) {
|
||||
DoricLog(@"JS:%@", message);
|
||||
}];
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_EMPTY obj:^() {
|
||||
|
||||
}];
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_REQUIRE obj:^(NSString *name) {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return NO;
|
||||
NSString *content = [self.registry acquireJSBundle:name];
|
||||
if (!content) {
|
||||
DoricLog(@"require js bundle:%@ is empty", name);
|
||||
return NO;
|
||||
}
|
||||
@try {
|
||||
[self.jsExecutor loadJSScript:[self packageModuleScript:name content:content]
|
||||
source:[@"Module://" stringByAppendingString:name]];
|
||||
} @catch (NSException *e) {
|
||||
DoricLog(@"require js bundle:%@ error,for %@", name, e.reason);
|
||||
}
|
||||
return YES;
|
||||
}];
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_TIMER_SET
|
||||
obj:^(NSNumber *timerId, NSNumber *interval, NSNumber *isInterval) {
|
||||
__strong typeof(_self) self = _self;
|
||||
NSString *timerId_str = [timerId stringValue];
|
||||
BOOL repeat = [isInterval boolValue];
|
||||
NSTimer *timer = [NSTimer timerWithTimeInterval:[interval doubleValue] / 1000 target:self selector:@selector(callbackTimer:) userInfo:@{@"timerId": timerId, @"repeat": isInterval} repeats:repeat];
|
||||
[self.timers setValue:timer forKey:timerId_str];
|
||||
dispatch_async(dispatch_get_main_queue(), ^() {
|
||||
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
|
||||
});
|
||||
}];
|
||||
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_TIMER_CLEAR
|
||||
obj:^(NSString *timerId) {
|
||||
__strong typeof(_self) self = _self;
|
||||
NSTimer *timer = [self.timers valueForKey:timerId];
|
||||
if (timer) {
|
||||
[timer invalidate];
|
||||
[self.timers removeObjectForKey:timerId];
|
||||
}
|
||||
}];
|
||||
|
||||
[self.jsExecutor injectGlobalJSObject:INJECT_BRIDGE obj:^(NSString *contextId, NSString *module, NSString *method, NSString *callbackId, id argument) {
|
||||
return [self.bridgeExtension callNativeWithContextId:contextId module:module method:method callbackId:callbackId argument:argument];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)initDoricEnvironment {
|
||||
[self loadBuiltinJS:DORIC_BUNDLE_SANDBOX];
|
||||
NSString *path = [DoricBundle() pathForResource:DORIC_BUNDLE_LIB ofType:@"js" inDirectory:@"bundle"];
|
||||
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||
[self.jsExecutor loadJSScript:[self packageModuleScript:DORIC_MODULE_LIB content:jsContent]
|
||||
source:[@"Module://" stringByAppendingString:DORIC_MODULE_LIB]];
|
||||
}
|
||||
|
||||
- (void)loadBuiltinJS:(NSString *)fileName {
|
||||
NSString *path = [DoricBundle() pathForResource:DORIC_BUNDLE_SANDBOX ofType:@"js" inDirectory:@"bundle"];
|
||||
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
|
||||
[self.jsExecutor loadJSScript:jsContent source:[@"Assets://" stringByAppendingString:fileName]];
|
||||
}
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method, ... {
|
||||
va_list args;
|
||||
va_start(args, method);
|
||||
JSValue *ret = [self invokeDoricMethod:method arguments:args];
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method arguments:(va_list)args {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
id arg = va_arg(args, id);
|
||||
while (arg != nil) {
|
||||
[array addObject:arg];
|
||||
arg = va_arg(args, JSValue *);
|
||||
}
|
||||
return [self.jsExecutor invokeObject:GLOBAL_DORIC method:method args:array];
|
||||
}
|
||||
|
||||
- (JSValue *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArray *)args {
|
||||
return [self.jsExecutor invokeObject:GLOBAL_DORIC method:method args:args];
|
||||
}
|
||||
|
||||
- (NSString *)packageContextScript:(NSString *)contextId content:(NSString *)content {
|
||||
NSString *ret = [NSString stringWithFormat:TEMPLATE_CONTEXT_CREATE, content, contextId, contextId, contextId];
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (NSString *)packageModuleScript:(NSString *)moduleName content:(NSString *)content {
|
||||
NSString *ret = [NSString stringWithFormat:TEMPLATE_MODULE, moduleName, content];
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)prepareContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source {
|
||||
[self.jsExecutor loadJSScript:[self packageContextScript:contextId content:script]
|
||||
source:[@"Context://" stringByAppendingString:source]];
|
||||
}
|
||||
|
||||
- (void)destroyContext:(NSString *)contextId {
|
||||
[self.jsExecutor loadJSScript:[NSString stringWithFormat:TEMPLATE_CONTEXT_DESTROY, contextId]
|
||||
source:[@"_Context://" stringByAppendingString:contextId]];
|
||||
}
|
||||
|
||||
- (void)callbackTimer:(NSTimer *)timer {
|
||||
NSDictionary *userInfo = timer.userInfo;
|
||||
NSNumber *timerId = [userInfo valueForKey:@"timerId"];
|
||||
NSNumber *repeat = [userInfo valueForKey:@"repeat"];
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(self.jsQueue, ^() {
|
||||
__strong typeof(_self) self = _self;
|
||||
@try {
|
||||
[self invokeDoricMethod:DORIC_TIMER_CALLBACK, timerId, nil];
|
||||
} @catch (NSException *exception) {
|
||||
DoricLog(@"Timer Callback error:%@", exception.reason);
|
||||
}
|
||||
if (![repeat boolValue]) {
|
||||
[self.timers removeObjectForKey:[timerId stringValue]];
|
||||
}
|
||||
});
|
||||
}
|
||||
@end
|
38
doric-iOS/Pod/Classes/Engine/DoricJSExecutorProtocol.h
Normal file
38
doric-iOS/Pod/Classes/Engine/DoricJSExecutorProtocol.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSEngineProtocal.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol DoricJSExecutorProtocol <NSObject>
|
||||
|
||||
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source;
|
||||
|
||||
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj;
|
||||
|
||||
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
35
doric-iOS/Pod/Classes/Engine/DoricJSRemoteExecutor.h
Normal file
35
doric-iOS/Pod/Classes/Engine/DoricJSRemoteExecutor.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSRemoteExecutor.h
|
||||
// Pods
|
||||
//
|
||||
// Created by 王劲鹏 on 2019/10/31.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricJSExecutorProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricJSRemoteExecutor : NSObject <DoricJSExecutorProtocol>
|
||||
|
||||
@property(nonatomic, strong) dispatch_semaphore_t semaphore;
|
||||
|
||||
- (void)close;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
193
doric-iOS/Pod/Classes/Engine/DoricJSRemoteExecutor.m
Normal file
193
doric-iOS/Pod/Classes/Engine/DoricJSRemoteExecutor.m
Normal file
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSRemoteExecutor.m
|
||||
// Doric
|
||||
//
|
||||
// Created by 王劲鹏 on 2019/10/31.
|
||||
//
|
||||
#import "DoricJSRemoteExecutor.h"
|
||||
#import <SocketRocket/SRWebSocket.h>
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricJSRemoteArgType.h"
|
||||
#import "NSString+JsonString.h"
|
||||
|
||||
static NSString * const kUrlStr = @"ws://192.168.24.240:2080";
|
||||
|
||||
typedef id (^Block0)(void);
|
||||
typedef id (^Block1)(id arg0);
|
||||
typedef id (^Block2)(id arg0, id arg1);
|
||||
typedef id (^Block3)(id arg0, id arg1, id arg2);
|
||||
typedef id (^Block4)(id arg0, id arg1, id arg2, id arg3);
|
||||
typedef id (^Block5)(id arg0, id arg1, id arg2, id arg3, id arg4);
|
||||
|
||||
@interface DoricJSRemoteExecutor () <SRWebSocketDelegate>
|
||||
@property(nonatomic, strong) SRWebSocket *srWebSocket;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSString *, id> *blockMDic;
|
||||
@property(nonatomic, strong) JSValue *temp;
|
||||
@end
|
||||
|
||||
@implementation DoricJSRemoteExecutor
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
[self srWebSocket];
|
||||
_semaphore = dispatch_semaphore_create(0);
|
||||
DC_LOCK(self.semaphore);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
|
||||
DoricLog(@"debugger webSocketDidOpen");
|
||||
DC_UNLOCK(self.semaphore);
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
|
||||
DoricLog(@"debugger webSocketdidReceivePong");
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
|
||||
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *err;
|
||||
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
|
||||
options:NSJSONReadingMutableContainers
|
||||
error:&err];
|
||||
if (err) {
|
||||
DoricLog(@"debugger webSocketdidReceiveMessage parse error:%@", err);
|
||||
return;
|
||||
}
|
||||
NSString *cmd = [[dic valueForKey:@"cmd"] copy];
|
||||
|
||||
if ([cmd isEqualToString:@"injectGlobalJSFunction"]) {
|
||||
NSString *name = [dic valueForKey:@"name"];
|
||||
NSArray *argsArr = [dic valueForKey:@"arguments"];
|
||||
NSMutableArray *argsMarr = [NSMutableArray new];
|
||||
for (NSUInteger i = 0; i < argsArr.count; i++) {
|
||||
[argsMarr addObject:argsArr[i]];
|
||||
}
|
||||
|
||||
id result;
|
||||
id tmpBlk = self.blockMDic[name];
|
||||
if (argsArr.count == 0) {
|
||||
result = ((Block0) tmpBlk)();
|
||||
} else if (argsArr.count == 1) {
|
||||
result = ((Block1) tmpBlk)(argsArr[0]);
|
||||
} else if (argsArr.count == 2) {
|
||||
result = ((Block2)tmpBlk)(argsArr[0], argsArr[1]);
|
||||
} else if (argsArr.count == 3) {
|
||||
result = ((Block3)tmpBlk)(argsArr[0], argsArr[1], argsArr[2]);
|
||||
} else if (argsArr.count == 4) {
|
||||
result = ((Block4)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3]);
|
||||
} else if (argsArr.count == 5) {
|
||||
result = ((Block5)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3], argsArr[4]);
|
||||
}
|
||||
|
||||
} else if ([cmd isEqualToString:@"invokeMethod"]) {
|
||||
@try {
|
||||
self.temp = [JSValue valueWithObject:[dic valueForKey:@"result"] inContext:nil];
|
||||
} @catch (NSException *exception) {
|
||||
DoricLog(@"debugger ", NSStringFromSelector(_cmd), exception.reason);
|
||||
} @finally {
|
||||
DC_UNLOCK(self.semaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
|
||||
DoricLog(@"debugger webSocketdidFailWithError");
|
||||
DC_UNLOCK(self.semaphore);
|
||||
}
|
||||
|
||||
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
|
||||
DoricLog(@"debugger webSocketdidCloseWithCode");
|
||||
}
|
||||
|
||||
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source {
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj {
|
||||
if ([obj isKindOfClass:NSClassFromString(@"NSBlock")]) {
|
||||
self.blockMDic[name] = obj;
|
||||
}
|
||||
NSDictionary *jsonDic = @{
|
||||
@"cmd": @"injectGlobalJSFunction",
|
||||
@"name": name
|
||||
};
|
||||
|
||||
NSString *jsonStr = [NSString dc_convertToJsonWithDic:jsonDic];
|
||||
if (!jsonStr) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.srWebSocket send:jsonStr];
|
||||
}
|
||||
|
||||
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args {
|
||||
|
||||
NSMutableArray *argsMArr = [NSMutableArray new];
|
||||
for (id arg in args) {
|
||||
NSDictionary *dic = @{
|
||||
@"type": @(DoricargTypeWithArg(arg)),
|
||||
@"value": arg
|
||||
};
|
||||
[argsMArr addObject:dic];
|
||||
}
|
||||
|
||||
NSArray *argsArr = [argsMArr copy];
|
||||
|
||||
NSDictionary *jsonDic = @{
|
||||
@"cmd": @"invokeMethod",
|
||||
@"objectName": objName,
|
||||
@"functionName": funcName,
|
||||
@"javaValues": argsArr
|
||||
};
|
||||
|
||||
NSString *jsonStr = [NSString dc_convertToJsonWithDic:jsonDic];
|
||||
if (!jsonStr) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[self.srWebSocket send:jsonStr];
|
||||
DC_LOCK(self.semaphore);
|
||||
|
||||
return self.temp;
|
||||
}
|
||||
|
||||
- (void)close {
|
||||
[self.srWebSocket close];
|
||||
}
|
||||
|
||||
#pragma mark - Properties
|
||||
- (SRWebSocket *)srWebSocket {
|
||||
if (!_srWebSocket) {
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kUrlStr] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
|
||||
_srWebSocket = [[SRWebSocket alloc] initWithURLRequest:request];
|
||||
_srWebSocket.delegate = self;
|
||||
[_srWebSocket open];
|
||||
}
|
||||
return _srWebSocket;
|
||||
}
|
||||
|
||||
- (NSMutableDictionary *)blockMDic {
|
||||
if (!_blockMDic) {
|
||||
_blockMDic = [NSMutableDictionary new];
|
||||
}
|
||||
return _blockMDic;
|
||||
}
|
||||
|
||||
@end
|
31
doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.h
Normal file
31
doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricBridgeExtension.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricBridgeExtension : NSObject
|
||||
- (id)callNativeWithContextId:(NSString *)contextId module:(NSString *)module method:(NSString *)method callbackId:(NSString *)callbackId argument:(id)argument;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
120
doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m
Normal file
120
doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricBridgeExtension.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricBridgeExtension.h"
|
||||
#import "DoricRegistry.h"
|
||||
#import "DoricContextManager.h"
|
||||
#import "DoricNativePlugin.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation DoricBridgeExtension
|
||||
|
||||
- (id)callNativeWithContextId:(NSString *)contextId module:(NSString *)module method:(NSString *)method callbackId:(NSString *)callbackId argument:(id)argument {
|
||||
DoricContext *context = [[DoricContextManager instance] getContext:contextId];
|
||||
DoricRegistry *registry = context.driver.registry;
|
||||
Class pluginClass = [registry acquireNativePlugin:module];
|
||||
DoricNativePlugin *nativePlugin = context.pluginInstanceMap[module];
|
||||
if (nativePlugin == nil) {
|
||||
nativePlugin = [(DoricNativePlugin *) [pluginClass alloc] initWithContext:context];
|
||||
context.pluginInstanceMap[module] = nativePlugin;
|
||||
}
|
||||
|
||||
return [self findClass:pluginClass target:nativePlugin context:context method:method callbackId:callbackId argument:argument];
|
||||
}
|
||||
|
||||
- (id)createParamWithMethodName:(NSString *)method context:(DoricContext *)context callbackId:(NSString *)callbackId argument:(id)argument {
|
||||
if ([method isEqualToString:@"withPromise"]) {
|
||||
return [[DoricPromise alloc] initWithContext:context callbackId:callbackId];
|
||||
}
|
||||
return argument;
|
||||
}
|
||||
|
||||
- (id)findClass:(Class)clz target:(id)target context:(DoricContext *)context method:(NSString *)name callbackId:(NSString *)callbackId argument:(id)argument {
|
||||
unsigned int count;
|
||||
id ret = nil;
|
||||
Method *methods = class_copyMethodList(clz, &count);
|
||||
BOOL isFound = NO;
|
||||
for (int i = 0; i < count; i++) {
|
||||
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
|
||||
NSArray *array = [methodName componentsSeparatedByString:@":"];
|
||||
if (array && [array count] > 0) {
|
||||
if ([array[0] isEqualToString:name]) {
|
||||
isFound = YES;
|
||||
SEL selector = NSSelectorFromString(methodName);
|
||||
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
|
||||
if (methodSignature) {
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
||||
invocation.selector = selector;
|
||||
invocation.target = target;
|
||||
__weak __typeof__(self) _self = self;
|
||||
dispatch_block_t block = ^() {
|
||||
__strong __typeof__(_self) self = _self;
|
||||
@try {
|
||||
for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) {
|
||||
if (idx - 2 > [array count]) {
|
||||
break;
|
||||
}
|
||||
id args = [self createParamWithMethodName:array[idx - 2] context:context callbackId:callbackId argument:argument];
|
||||
[invocation setArgument:&args atIndex:idx];
|
||||
}
|
||||
[invocation invoke];
|
||||
} @catch (NSException *exception) {
|
||||
DoricLog(@"CallNative Error:%@", exception.reason);
|
||||
}
|
||||
};
|
||||
|
||||
const char *retType = methodSignature.methodReturnType;
|
||||
if (!strcmp(retType, @encode(void))) {
|
||||
ret = nil;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
|
||||
} else if (!strcmp(retType, @encode(id))) {
|
||||
void *retValue;
|
||||
block();
|
||||
[invocation getReturnValue:&retValue];
|
||||
id returnValue = (__bridge id) retValue;
|
||||
ret = [JSValue valueWithObject:[returnValue copy] inContext:[JSContext currentContext]];
|
||||
} else {
|
||||
DoricLog(@"CallNative Error:%@", @"Must return object type");
|
||||
ret = nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (methods) {
|
||||
free(methods);
|
||||
}
|
||||
if (!isFound) {
|
||||
Class superclass = class_getSuperclass(clz);
|
||||
if (superclass && superclass != [NSObject class]) {
|
||||
return [self findClass:superclass target:target context:context method:name callbackId:callbackId argument:argument];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
}
|
||||
@end
|
25
doric-iOS/Pod/Classes/Loader/DoricHttpJSLoader.h
Normal file
25
doric-iOS/Pod/Classes/Loader/DoricHttpJSLoader.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricLoaderProtocol.h"
|
||||
|
||||
@interface DoricHttpJSLoader : NSObject <DoricLoaderProtocol>
|
||||
@end
|
45
doric-iOS/Pod/Classes/Loader/DoricHttpJSLoader.m
Normal file
45
doric-iOS/Pod/Classes/Loader/DoricHttpJSLoader.m
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricHttpJSLoader.h"
|
||||
|
||||
|
||||
@implementation DoricHttpJSLoader
|
||||
|
||||
- (BOOL)filter:(NSString *)scheme {
|
||||
return [scheme hasPrefix:@"http"];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
|
||||
DoricAsyncResult *ret = [DoricAsyncResult new];
|
||||
NSURL *URL = [NSURL URLWithString:scheme];
|
||||
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
|
||||
[[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]
|
||||
dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
if (!error) {
|
||||
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
[ret setupResult:dataStr];
|
||||
} else {
|
||||
[ret setupError:[[NSException alloc] initWithName:@"DoricJSLoaderManager Exception" reason:error.description userInfo:nil]];
|
||||
}
|
||||
}] resume];
|
||||
return ret;
|
||||
}
|
||||
@end
|
33
doric-iOS/Pod/Classes/Loader/DoricJSLoaderManager.h
Normal file
33
doric-iOS/Pod/Classes/Loader/DoricJSLoaderManager.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSLoaderManager.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricLoaderProtocol.h"
|
||||
#import "DoricAsyncResult.h"
|
||||
|
||||
@interface DoricJSLoaderManager : NSObject
|
||||
+ (instancetype)instance;
|
||||
|
||||
- (void)addJSLoader:(id <DoricLoaderProtocol>)loader;
|
||||
|
||||
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme;
|
||||
@end
|
68
doric-iOS/Pod/Classes/Loader/DoricJSLoaderManager.m
Normal file
68
doric-iOS/Pod/Classes/Loader/DoricJSLoaderManager.m
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricJSLoaderManager.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricJSLoaderManager.h"
|
||||
#import "DoricMainBundleJSLoader.h"
|
||||
#import "DoricHttpJSLoader.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricJSLoaderManager ()
|
||||
@property(nonatomic, copy) NSSet <id <DoricLoaderProtocol>> *loaders;
|
||||
@end
|
||||
|
||||
@implementation DoricJSLoaderManager
|
||||
+ (instancetype)instance {
|
||||
static DoricJSLoaderManager *_instance;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_instance = [DoricJSLoaderManager new];
|
||||
});
|
||||
return _instance;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_loaders = [[NSSet alloc] initWithArray:@[
|
||||
[DoricMainBundleJSLoader new],
|
||||
[DoricHttpJSLoader new],
|
||||
]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)addJSLoader:(id <DoricLoaderProtocol>)loader {
|
||||
self.loaders = [[self.loaders mutableCopy] also:^(NSMutableSet *it) {
|
||||
[it addObject:loader];
|
||||
}];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
|
||||
__block DoricAsyncResult *ret;
|
||||
[self.loaders enumerateObjectsUsingBlock:^(id <DoricLoaderProtocol> obj, BOOL *stop) {
|
||||
if ([obj filter:scheme]) {
|
||||
ret = [obj request:scheme];
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
return ret;
|
||||
}
|
||||
@end
|
27
doric-iOS/Pod/Classes/Loader/DoricLoaderProtocol.h
Normal file
27
doric-iOS/Pod/Classes/Loader/DoricLoaderProtocol.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricAsyncResult.h"
|
||||
|
||||
@protocol DoricLoaderProtocol <NSObject>
|
||||
- (BOOL)filter:(NSString *)scheme;
|
||||
|
||||
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme;
|
||||
@end
|
25
doric-iOS/Pod/Classes/Loader/DoricMainBundleJSLoader.h
Normal file
25
doric-iOS/Pod/Classes/Loader/DoricMainBundleJSLoader.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricLoaderProtocol.h"
|
||||
|
||||
@interface DoricMainBundleJSLoader : NSObject <DoricLoaderProtocol>
|
||||
@end
|
42
doric-iOS/Pod/Classes/Loader/DoricMainBundleJSLoader.m
Normal file
42
doric-iOS/Pod/Classes/Loader/DoricMainBundleJSLoader.m
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricMainBundleJSLoader.h"
|
||||
|
||||
|
||||
@implementation DoricMainBundleJSLoader
|
||||
- (BOOL)filter:(NSString *)scheme {
|
||||
return [scheme hasPrefix:@"assets"];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
|
||||
DoricAsyncResult <NSString *> *ret = [DoricAsyncResult new];
|
||||
NSString *path = [[NSBundle mainBundle] bundlePath];
|
||||
NSString *fullPath = [path stringByAppendingPathComponent:[scheme substringFromIndex:@"assets://".length]];
|
||||
NSError *error;
|
||||
NSString *jsContent = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (error) {
|
||||
[ret setupError:[NSException new]];
|
||||
} else {
|
||||
[ret setupResult:jsContent];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
31
doric-iOS/Pod/Classes/NavBar/DoricNavBarDelegate.h
Normal file
31
doric-iOS/Pod/Classes/NavBar/DoricNavBarDelegate.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@protocol DoricNavBarDelegate <NSObject>
|
||||
- (BOOL)doric_navBar_isHidden;
|
||||
|
||||
- (void)doric_navBar_setHidden:(BOOL)hidden;
|
||||
|
||||
- (void)doric_navBar_setTitle:(NSString *)title;
|
||||
|
||||
- (void)doric_navBar_setBackgroundColor:(UIColor *)color;
|
||||
@end
|
26
doric-iOS/Pod/Classes/Navigator/DoricNavigatorDelegate.h
Normal file
26
doric-iOS/Pod/Classes/Navigator/DoricNavigatorDelegate.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol DoricNavigatorDelegate <NSObject>
|
||||
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated;
|
||||
|
||||
- (void)doric_navigator_pop:(BOOL)animated;
|
||||
@end
|
10
doric-iOS/Pod/Classes/Plugin/DoricAnimatePlugin.h
Normal file
10
doric-iOS/Pod/Classes/Plugin/DoricAnimatePlugin.h
Normal file
@@ -0,0 +1,10 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricAnimatePlugin : DoricNativePlugin
|
||||
@end
|
33
doric-iOS/Pod/Classes/Plugin/DoricAnimatePlugin.m
Normal file
33
doric-iOS/Pod/Classes/Plugin/DoricAnimatePlugin.m
Normal file
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/29.
|
||||
//
|
||||
|
||||
#import "DoricAnimatePlugin.h"
|
||||
#import "DoricRootNode.h"
|
||||
|
||||
@implementation DoricAnimatePlugin
|
||||
|
||||
- (void)submit:(NSDictionary *)args withPromise:(DoricPromise *)promise {
|
||||
[promise resolve:nil];
|
||||
}
|
||||
|
||||
- (void)animateRender:(NSDictionary *)args withPromise:(DoricPromise *)promise {
|
||||
NSNumber *duration = args[@"duration"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
NSString *viewId = args[@"id"];
|
||||
[UIView animateWithDuration:[duration floatValue] / 1000
|
||||
animations:^{
|
||||
if (self.doricContext.rootNode.viewId == nil) {
|
||||
self.doricContext.rootNode.viewId = viewId;
|
||||
[self.doricContext.rootNode blend:args[@"props"]];
|
||||
} else {
|
||||
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
|
||||
[viewNode blend:args[@"props"]];
|
||||
}
|
||||
}
|
||||
completion:^(BOOL finished) {
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
});
|
||||
}
|
||||
@end
|
32
doric-iOS/Pod/Classes/Plugin/DoricModalPlugin.h
Normal file
32
doric-iOS/Pod/Classes/Plugin/DoricModalPlugin.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricModalPlugin.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricModalPlugin : DoricNativePlugin
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
115
doric-iOS/Pod/Classes/Plugin/DoricModalPlugin.m
Normal file
115
doric-iOS/Pod/Classes/Plugin/DoricModalPlugin.m
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricModalPlugin.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Doric/Doric.h>
|
||||
#import "DoricModalPlugin.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
@implementation DoricModalPlugin
|
||||
|
||||
- (void)toast:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__block DoricGravity gravity = BOTTOM;
|
||||
[dic[@"gravity"] also:^(NSNumber *it) {
|
||||
gravity = (DoricGravity) [it integerValue];
|
||||
}];
|
||||
ShowToast(dic[@"msg"], gravity);
|
||||
});
|
||||
}
|
||||
|
||||
- (void)alert:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
|
||||
message:dic[@"msg"]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertAction *action = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"OK", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
[alert addAction:action];
|
||||
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||
[vc presentViewController:alert animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)confirm:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
|
||||
message:dic[@"msg"]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"Ok", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
[alert addAction:okAction];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:dic[@"cancelLabel"] ?: NSLocalizedString(@"Cancel", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[promise reject:nil];
|
||||
}];
|
||||
[alert addAction:cancelAction];
|
||||
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||
[vc presentViewController:alert animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)prompt:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
|
||||
message:dic[@"msg"]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
NSString *placeholder = dic[@"defaultText"];
|
||||
NSString *preText = dic[@"text"];
|
||||
[alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
|
||||
if (placeholder.length > 0) {
|
||||
textField.placeholder = placeholder;
|
||||
}
|
||||
if (preText.length > 0) {
|
||||
textField.text = preText;
|
||||
}
|
||||
}];
|
||||
__weak typeof(alert) _alert = alert;
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"Ok", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
__strong typeof(_alert) alert = _alert;
|
||||
[promise resolve:alert.textFields.lastObject.text];
|
||||
}];
|
||||
[alert addAction:okAction];
|
||||
|
||||
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:dic[@"cancelLabel"] ?: NSLocalizedString(@"Cancel", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
__strong typeof(_alert) alert = _alert;
|
||||
[promise reject:alert.textFields.lastObject.text];
|
||||
}];
|
||||
[alert addAction:cancelAction];
|
||||
|
||||
|
||||
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
|
||||
[vc presentViewController:alert animated:YES completion:nil];
|
||||
});
|
||||
}
|
||||
@end
|
34
doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h
Normal file
34
doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricNativePlugin.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricContextHolder.h"
|
||||
#import "DoricPromise.h"
|
||||
#import "DoricRegistry.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricNativePlugin : DoricContextHolder
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
27
doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m
Normal file
27
doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricNativePlugin.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@implementation DoricNativePlugin
|
||||
|
||||
@end
|
26
doric-iOS/Pod/Classes/Plugin/DoricNavBarPlugin.h
Normal file
26
doric-iOS/Pod/Classes/Plugin/DoricNavBarPlugin.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/25.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricNavBarPlugin : DoricNativePlugin
|
||||
|
||||
@end
|
68
doric-iOS/Pod/Classes/Plugin/DoricNavBarPlugin.m
Normal file
68
doric-iOS/Pod/Classes/Plugin/DoricNavBarPlugin.m
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/25.
|
||||
//
|
||||
|
||||
#import "DoricNavBarPlugin.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
@implementation DoricNavBarPlugin
|
||||
- (void)isHidden:(NSDictionary *)param withPromise:(DoricPromise *)promise {
|
||||
if (self.doricContext.navBar) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[promise resolve:@([self.doricContext.navBar doric_navBar_isHidden])];
|
||||
});
|
||||
} else {
|
||||
[promise reject:@"Not implement NavBar"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setHidden:(NSDictionary *)param withPromise:(DoricPromise *)promise {
|
||||
if (self.doricContext.navBar) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.doricContext.navBar doric_navBar_setHidden:[param[@"hidden"] boolValue]];
|
||||
[promise resolve:nil];
|
||||
});
|
||||
} else {
|
||||
[promise reject:@"Not implement NavBar"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setTitle:(NSDictionary *)param withPromise:(DoricPromise *)promise {
|
||||
if (self.doricContext.navBar) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.doricContext.navBar doric_navBar_setTitle:param[@"title"]];
|
||||
[promise resolve:nil];
|
||||
});
|
||||
} else {
|
||||
[promise reject:@"Not implement NavBar"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setBgColor:(NSDictionary *)param withPromise:(DoricPromise *)promise {
|
||||
if (self.doricContext.navBar) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIColor *color = DoricColor(param[@"color"]);
|
||||
[self.doricContext.navBar doric_navBar_setBackgroundColor:color];
|
||||
[promise resolve:nil];
|
||||
});
|
||||
} else {
|
||||
[promise reject:@"Not implement NavBar"];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
24
doric-iOS/Pod/Classes/Plugin/DoricNavigatorPlugin.h
Normal file
24
doric-iOS/Pod/Classes/Plugin/DoricNavigatorPlugin.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricNavigatorPlugin : DoricNativePlugin
|
||||
@end
|
43
doric-iOS/Pod/Classes/Plugin/DoricNavigatorPlugin.m
Normal file
43
doric-iOS/Pod/Classes/Plugin/DoricNavigatorPlugin.m
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/23.
|
||||
//
|
||||
|
||||
#import "DoricNavigatorPlugin.h"
|
||||
|
||||
|
||||
@implementation DoricNavigatorPlugin
|
||||
- (void)push:(NSDictionary *)params {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
BOOL animated = YES;
|
||||
if (params[@"animated"]) {
|
||||
animated = [params[@"animated"] boolValue];
|
||||
}
|
||||
[self.doricContext.navigator doric_navigator_push:params[@"scheme"] alias:params[@"alias"] animated:animated];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)pop:(NSDictionary *)params {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
BOOL animated = YES;
|
||||
if (params[@"animated"]) {
|
||||
animated = [params[@"animated"] boolValue];
|
||||
}
|
||||
[self.doricContext.navigator doric_navigator_pop:animated];
|
||||
});
|
||||
}
|
||||
@end
|
24
doric-iOS/Pod/Classes/Plugin/DoricNetworkPlugin.h
Normal file
24
doric-iOS/Pod/Classes/Plugin/DoricNetworkPlugin.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/21.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricNetworkPlugin : DoricNativePlugin
|
||||
@end
|
59
doric-iOS/Pod/Classes/Plugin/DoricNetworkPlugin.m
Normal file
59
doric-iOS/Pod/Classes/Plugin/DoricNetworkPlugin.m
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/21.
|
||||
//
|
||||
|
||||
#import "DoricNetworkPlugin.h"
|
||||
|
||||
|
||||
@implementation DoricNetworkPlugin
|
||||
- (void)request:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
|
||||
NSString *url = dic[@"url"];
|
||||
NSString *method = dic[@"method"];
|
||||
NSDictionary <NSString *, NSString *> *headers = dic[@"headers"];
|
||||
NSNumber *timeout = dic[@"timeout"];
|
||||
NSString *data = dic[@"data"];
|
||||
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
|
||||
request.HTTPMethod = method.uppercaseString;
|
||||
if (timeout) {
|
||||
request.timeoutInterval = [timeout floatValue] / 1000;
|
||||
}
|
||||
if (headers) {
|
||||
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
|
||||
[request setValue:obj forHTTPHeaderField:key];
|
||||
}];
|
||||
}
|
||||
if (data) {
|
||||
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
|
||||
}
|
||||
[[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]
|
||||
dataTaskWithRequest:request
|
||||
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
||||
if (!error) {
|
||||
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
NSDictionary *resDic = @{
|
||||
@"status": @(((NSHTTPURLResponse *) response).statusCode),
|
||||
@"headers": ((NSHTTPURLResponse *) response).allHeaderFields,
|
||||
@"data": dataStr,
|
||||
};
|
||||
[promise resolve:resDic];
|
||||
} else {
|
||||
[promise reject:error.description];
|
||||
}
|
||||
}] resume];
|
||||
}
|
||||
@end
|
9
doric-iOS/Pod/Classes/Plugin/DoricPopoverPlugin.h
Normal file
9
doric-iOS/Pod/Classes/Plugin/DoricPopoverPlugin.h
Normal file
@@ -0,0 +1,9 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricPopoverPlugin : DoricNativePlugin
|
||||
@end
|
70
doric-iOS/Pod/Classes/Plugin/DoricPopoverPlugin.m
Normal file
70
doric-iOS/Pod/Classes/Plugin/DoricPopoverPlugin.m
Normal file
@@ -0,0 +1,70 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import "DoricPopoverPlugin.h"
|
||||
#import "DoricRootNode.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricPopoverPlugin ()
|
||||
@property(nonatomic, strong) UIView *fullScreenView;
|
||||
@end
|
||||
|
||||
@implementation DoricPopoverPlugin
|
||||
- (void)show:(NSDictionary *)params withPromise:(DoricPromise *)promise {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIView *superView = [UIApplication sharedApplication].windows.lastObject;
|
||||
if (!self.fullScreenView) {
|
||||
self.fullScreenView = [[DoricStackView new] also:^(UIView *it) {
|
||||
it.width = superView.width;
|
||||
it.height = superView.height;
|
||||
it.top = it.left = 0;
|
||||
[superView addSubview:it];
|
||||
}];
|
||||
}
|
||||
[superView bringSubviewToFront:self.fullScreenView];
|
||||
self.fullScreenView.hidden = NO;
|
||||
NSString *viewId = params[@"id"];
|
||||
NSString *type = params[@"type"];
|
||||
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
|
||||
if (!viewNode) {
|
||||
viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:nil];
|
||||
it.view.layoutConfig = [DoricLayoutConfig new];
|
||||
[self.fullScreenView addSubview:it.view];
|
||||
self.doricContext.headNodes[viewId] = it;
|
||||
}];
|
||||
}
|
||||
[viewNode blend:params[@"props"]];
|
||||
[promise resolve:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dismiss:(NSDictionary *)params withPromise:(DoricPromise *)promise {
|
||||
NSString *viewId = params[@"id"];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (viewId) {
|
||||
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
|
||||
[self dismissViewNode:viewNode];
|
||||
} else {
|
||||
[self dismissPopover];
|
||||
}
|
||||
[promise resolve:nil];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)dismissViewNode:(DoricViewNode *)node {
|
||||
[self.doricContext.headNodes removeObjectForKey:node.viewId];
|
||||
[node.view removeFromSuperview];
|
||||
if (self.doricContext.headNodes.count == 0) {
|
||||
self.fullScreenView.hidden = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dismissPopover {
|
||||
for (DoricViewNode *node in self.doricContext.headNodes.allValues) {
|
||||
[self dismissViewNode:node];
|
||||
}
|
||||
}
|
||||
@end
|
32
doric-iOS/Pod/Classes/Plugin/DoricPromise.h
Normal file
32
doric-iOS/Pod/Classes/Plugin/DoricPromise.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricPromise.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricContext.h"
|
||||
|
||||
@interface DoricPromise : NSObject
|
||||
- (instancetype)initWithContext:(DoricContext *)context callbackId:(NSString *)callbackId;
|
||||
|
||||
- (void)resolve:(id)result;
|
||||
|
||||
- (void)reject:(id)result;
|
||||
@end
|
49
doric-iOS/Pod/Classes/Plugin/DoricPromise.m
Normal file
49
doric-iOS/Pod/Classes/Plugin/DoricPromise.m
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricPromise.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricPromise.h"
|
||||
#import "DoricConstant.h"
|
||||
|
||||
@interface DoricPromise ()
|
||||
@property(nonatomic, strong) DoricContext *context;
|
||||
@property(nonatomic, strong) NSString *callbackId;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricPromise
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)context callbackId:(NSString *)callbackId {
|
||||
if (self = [super init]) {
|
||||
_context = context;
|
||||
_callbackId = callbackId;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)resolve:(id)result {
|
||||
[self.context.driver invokeDoricMethod:DORIC_BRIDGE_RESOLVE, self.context.contextId, self.callbackId, result, nil];
|
||||
}
|
||||
|
||||
- (void)reject:(id)result {
|
||||
[self.context.driver invokeDoricMethod:DORIC_BRIDGE_REJECT, self.context.contextId, self.callbackId, result, nil];
|
||||
}
|
||||
@end
|
32
doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.h
Normal file
32
doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricShaderPlugin.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricShaderPlugin : DoricNativePlugin
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
143
doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m
Normal file
143
doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricShaderPlugin.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/29.
|
||||
//
|
||||
|
||||
#import "DoricShaderPlugin.h"
|
||||
#import "DoricRootNode.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation DoricShaderPlugin
|
||||
|
||||
- (void)render:(NSDictionary *)argument {
|
||||
if (!argument) {
|
||||
return;
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
__strong typeof(_self) self = _self;
|
||||
|
||||
NSString *viewId = argument[@"id"];
|
||||
|
||||
if (self.doricContext.rootNode.viewId == nil) {
|
||||
self.doricContext.rootNode.viewId = viewId;
|
||||
[self.doricContext.rootNode blend:argument[@"props"]];
|
||||
} else {
|
||||
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
|
||||
[viewNode blend:argument[@"props"]];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (id)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
|
||||
NSArray *viewIds = argument[@"viewIds"];
|
||||
id args = argument[@"args"];
|
||||
NSString *name = argument[@"name"];
|
||||
DoricViewNode *viewNode = nil;
|
||||
for (NSString *viewId in viewIds) {
|
||||
if (!viewNode) {
|
||||
viewNode = [self.doricContext targetViewNode:viewId];
|
||||
} else {
|
||||
if ([viewNode isKindOfClass:[DoricSuperNode class]]) {
|
||||
viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!viewNode) {
|
||||
[promise reject:@"Cannot find opposite view"];
|
||||
return nil;
|
||||
} else {
|
||||
return [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument {
|
||||
if ([method isEqualToString:@"withPromise"]) {
|
||||
return promise;
|
||||
}
|
||||
return argument;
|
||||
}
|
||||
|
||||
- (id)findClass:(Class)clz target:(id)target method:(NSString *)name promise:(DoricPromise *)promise argument:(id)argument {
|
||||
unsigned int count;
|
||||
id ret = nil;
|
||||
Method *methods = class_copyMethodList(clz, &count);
|
||||
BOOL isFound = NO;
|
||||
for (int i = 0; i < count; i++) {
|
||||
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
|
||||
NSArray *array = [methodName componentsSeparatedByString:@":"];
|
||||
if (array && [array count] > 0) {
|
||||
if ([array[0] isEqualToString:name]) {
|
||||
isFound = YES;
|
||||
SEL selector = NSSelectorFromString(methodName);
|
||||
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
|
||||
if (methodSignature) {
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
|
||||
invocation.selector = selector;
|
||||
invocation.target = target;
|
||||
__weak __typeof__(self) _self = self;
|
||||
dispatch_block_t block = ^() {
|
||||
__strong __typeof__(_self) self = _self;
|
||||
@try {
|
||||
for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) {
|
||||
if (idx - 2 > [array count]) {
|
||||
break;
|
||||
}
|
||||
id param = [self createParamWithMethodName:array[idx - 2] promise:promise argument:argument];
|
||||
[invocation setArgument:¶m atIndex:idx];
|
||||
}
|
||||
[invocation invoke];
|
||||
} @catch (NSException *exception) {
|
||||
DoricLog(@"CallNative Error:%@", exception.reason);
|
||||
}
|
||||
};
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
void *retValue;
|
||||
block();
|
||||
const char *retType = methodSignature.methodReturnType;
|
||||
if (!strcmp(retType, @encode(void))) {
|
||||
} else {
|
||||
[invocation getReturnValue:&retValue];
|
||||
id returnValue = (__bridge id) retValue;
|
||||
[promise resolve:returnValue];
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (methods) {
|
||||
free(methods);
|
||||
}
|
||||
if (!isFound) {
|
||||
Class superclass = class_getSuperclass(clz);
|
||||
if (superclass && superclass != [NSObject class]) {
|
||||
return [self findClass:superclass target:target method:name promise:promise argument:argument];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
24
doric-iOS/Pod/Classes/Plugin/DoricStoragePlugin.h
Normal file
24
doric-iOS/Pod/Classes/Plugin/DoricStoragePlugin.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/22.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricNativePlugin.h"
|
||||
|
||||
@interface DoricStoragePlugin : DoricNativePlugin
|
||||
@end
|
98
doric-iOS/Pod/Classes/Plugin/DoricStoragePlugin.m
Normal file
98
doric-iOS/Pod/Classes/Plugin/DoricStoragePlugin.m
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/22.
|
||||
//
|
||||
|
||||
#import "DoricStoragePlugin.h"
|
||||
#import "YYDiskCache.h"
|
||||
|
||||
static NSString *doric_prefix = @"pref";
|
||||
|
||||
@interface DoricStoragePlugin ()
|
||||
@property(atomic, strong) NSMutableDictionary <NSString *, YYDiskCache *> *cachedMap;
|
||||
@property(nonatomic, strong) YYDiskCache *defaultCache;
|
||||
@property(nonatomic, copy) NSString *basePath;
|
||||
@end
|
||||
|
||||
@implementation DoricStoragePlugin
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_basePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
|
||||
stringByAppendingPathComponent:@"doric"];
|
||||
_cachedMap = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (YYDiskCache *)defaultCache {
|
||||
if (!_defaultCache) {
|
||||
_defaultCache = [[YYDiskCache alloc] initWithPath:[self.basePath stringByAppendingPathComponent:doric_prefix]];
|
||||
}
|
||||
return _defaultCache;
|
||||
}
|
||||
|
||||
- (YYDiskCache *)getDiskCache:(NSString *)zone {
|
||||
YYDiskCache *diskCache;
|
||||
if (zone) {
|
||||
diskCache = self.cachedMap[zone];
|
||||
if (!diskCache) {
|
||||
diskCache = [[YYDiskCache alloc] initWithPath:[self.basePath
|
||||
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@", doric_prefix, zone]]];
|
||||
self.cachedMap[zone] = diskCache;
|
||||
}
|
||||
} else {
|
||||
diskCache = self.defaultCache;
|
||||
}
|
||||
return diskCache;
|
||||
}
|
||||
|
||||
- (void)setItem:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
|
||||
NSString *zone = argument[@"zone"];
|
||||
NSString *key = argument[@"key"];
|
||||
NSString *value = argument[@"value"];
|
||||
YYDiskCache *diskCache = [self getDiskCache:zone];
|
||||
[diskCache setObject:value forKey:key withBlock:^{
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)getItem:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
|
||||
NSString *zone = argument[@"zone"];
|
||||
NSString *key = argument[@"key"];
|
||||
YYDiskCache *diskCache = [self getDiskCache:zone];
|
||||
[diskCache objectForKey:key withBlock:^(NSString *key, NSString *value) {
|
||||
[promise resolve:value];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)remove:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
|
||||
NSString *zone = argument[@"zone"];
|
||||
NSString *key = argument[@"key"];
|
||||
YYDiskCache *diskCache = [self getDiskCache:zone];
|
||||
[diskCache removeObjectForKey:key withBlock:^(NSString *key) {
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)clear:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
|
||||
NSString *zone = argument[@"zone"];
|
||||
YYDiskCache *diskCache = [self getDiskCache:zone];
|
||||
[diskCache removeAllObjectsWithBlock:^{
|
||||
[promise resolve:nil];
|
||||
}];
|
||||
}
|
||||
@end
|
25
doric-iOS/Pod/Classes/Refresh/DoricRefreshableNode.h
Normal file
25
doric-iOS/Pod/Classes/Refresh/DoricRefreshableNode.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
#import "DoricSwipeRefreshLayout.h"
|
||||
|
||||
@interface DoricRefreshableNode : DoricSuperNode<DoricSwipeRefreshLayout *>
|
||||
@end
|
176
doric-iOS/Pod/Classes/Refresh/DoricRefreshableNode.m
Normal file
176
doric-iOS/Pod/Classes/Refresh/DoricRefreshableNode.m
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import "DoricRefreshableNode.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricRefreshableNode () <DoricSwipePullingDelegate>
|
||||
@property(nonatomic, strong) DoricViewNode *contentNode;
|
||||
@property(nonatomic, copy) NSString *contentViewId;
|
||||
@property(nonatomic, strong) DoricViewNode *headerNode;
|
||||
@property(nonatomic, copy) NSString *headerViewId;
|
||||
@end
|
||||
|
||||
@implementation DoricRefreshableNode
|
||||
- (DoricSwipeRefreshLayout *)build {
|
||||
return [[DoricSwipeRefreshLayout new] also:^(DoricSwipeRefreshLayout *it) {
|
||||
it.swipePullingDelegate = self;
|
||||
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricSwipeRefreshLayout *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"content" isEqualToString:name]) {
|
||||
self.contentViewId = prop;
|
||||
} else if ([@"header" isEqualToString:name]) {
|
||||
self.headerViewId = prop;
|
||||
} else if ([@"onRefresh" isEqualToString:name]) {
|
||||
__weak typeof(self) _self = self;
|
||||
NSString *funcId = prop;
|
||||
self.view.onRefreshBlock = ^{
|
||||
__strong typeof(_self) self = _self;
|
||||
[self callJSResponse:funcId, nil];
|
||||
};
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
if ([viewId isEqualToString:self.contentViewId]) {
|
||||
return self.contentNode;
|
||||
} else if ([viewId isEqualToString:self.headerViewId]) {
|
||||
return self.headerNode;
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
[self blendContent];
|
||||
[self blendHeader];
|
||||
}
|
||||
|
||||
- (void)blendContent {
|
||||
NSDictionary *contentModel = [self subModelOf:self.contentViewId];
|
||||
if (!contentModel) {
|
||||
return;
|
||||
}
|
||||
NSString *viewId = contentModel[@"id"];
|
||||
NSString *type = contentModel[@"type"];
|
||||
NSDictionary *childProps = contentModel[@"props"];
|
||||
if (self.contentNode) {
|
||||
if ([self.contentNode.viewId isEqualToString:viewId]) {
|
||||
//skip
|
||||
} else {
|
||||
if (self.reusable && [type isEqualToString:self.contentNode.type]) {
|
||||
[self.contentNode also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it blend:childProps];
|
||||
}];
|
||||
} else {
|
||||
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendHeader {
|
||||
NSDictionary *headerModel = [self subModelOf:self.headerViewId];
|
||||
if (!headerModel) {
|
||||
return;
|
||||
}
|
||||
NSString *viewId = headerModel[@"id"];
|
||||
NSString *type = headerModel[@"type"];
|
||||
NSDictionary *childProps = headerModel[@"props"];
|
||||
if (self.headerNode) {
|
||||
if ([self.headerNode.viewId isEqualToString:viewId]) {
|
||||
//skip
|
||||
} else {
|
||||
if (self.reusable && [type isEqualToString:self.headerNode.type]) {
|
||||
[self.headerNode also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it blend:childProps];
|
||||
}];
|
||||
} else {
|
||||
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.headerView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.headerView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
[[self subNodeWithViewId:subModel[@"id"]] blend:subModel[@"props"]];
|
||||
}
|
||||
|
||||
- (void)startAnimation {
|
||||
[self.headerNode callJSResponse:@"startAnimation", nil];
|
||||
}
|
||||
|
||||
- (void)stopAnimation {
|
||||
[self.headerNode callJSResponse:@"stopAnimation", nil];
|
||||
}
|
||||
|
||||
- (void)setPullingDistance:(CGFloat)distance {
|
||||
[self.headerNode callJSResponse:@"setPullingDistance", @(distance), nil];
|
||||
}
|
||||
|
||||
- (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise {
|
||||
self.view.refreshing = [refreshable boolValue];
|
||||
[promise resolve:nil];
|
||||
}
|
||||
|
||||
- (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise {
|
||||
self.view.refreshable = [refreshing boolValue];
|
||||
[promise resolve:nil];
|
||||
}
|
||||
|
||||
- (NSNumber *)isRefreshing {
|
||||
return @(self.view.refreshing);
|
||||
}
|
||||
|
||||
- (NSNumber *)isRefreshable {
|
||||
return @(self.view.refreshable);
|
||||
}
|
||||
@end
|
22
doric-iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h
Normal file
22
doric-iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.h
Normal file
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@protocol DoricSwipePullingDelegate <NSObject>
|
||||
- (void)startAnimation;
|
||||
|
||||
- (void)stopAnimation;
|
||||
|
||||
- (void)setPullingDistance:(CGFloat)rotation;
|
||||
@end
|
||||
|
||||
@interface DoricSwipeRefreshLayout : UIScrollView
|
||||
@property(nonatomic, strong) UIView *contentView;
|
||||
@property(nonatomic, strong) UIView *headerView;
|
||||
@property(nonatomic, assign) BOOL refreshable;
|
||||
@property(nonatomic, assign) BOOL refreshing;
|
||||
@property(nonatomic, strong) void (^onRefreshBlock)(void);
|
||||
@property(nonatomic, weak) id <DoricSwipePullingDelegate> swipePullingDelegate;
|
||||
@end
|
159
doric-iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m
Normal file
159
doric-iOS/Pod/Classes/Refresh/DoricSwipeRefreshLayout.m
Normal file
@@ -0,0 +1,159 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/26.
|
||||
//
|
||||
|
||||
#import "DoricSwipeRefreshLayout.h"
|
||||
#import "UIView+Doric.h"
|
||||
#import "DoricLayouts.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@interface DoricSwipeRefreshLayout () <UIScrollViewDelegate>
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricSwipeRefreshLayout
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.alwaysBounceVertical = YES;
|
||||
self.delegate = self;
|
||||
if (@available(iOS 11, *)) {
|
||||
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
self.showsHorizontalScrollIndicator = NO;
|
||||
self.showsVerticalScrollIndicator = NO;
|
||||
self.alwaysBounceVertical = YES;
|
||||
self.delegate = self;
|
||||
if (@available(iOS 11, *)) {
|
||||
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.contentView) {
|
||||
return [self.contentView measureSize:size];
|
||||
}
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (BOOL)requestFromSubview:(UIView *)subview {
|
||||
if (subview == self.headerView) {
|
||||
return NO;
|
||||
}
|
||||
return [super requestFromSubview:subview];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
if (self.contentOffset.y != 0) {
|
||||
return;
|
||||
}
|
||||
self.width = targetSize.width;
|
||||
self.height = targetSize.height;
|
||||
[self.headerView also:^(UIView *it) {
|
||||
[it layoutSelf:[it measureSize:targetSize]];
|
||||
it.bottom = 0;
|
||||
it.centerX = self.centerX;
|
||||
}];
|
||||
[self.contentView also:^(UIView *it) {
|
||||
[it layoutSelf:targetSize];
|
||||
}];
|
||||
self.contentSize = self.frame.size;
|
||||
}
|
||||
|
||||
- (void)setContentView:(UIView *)contentView {
|
||||
if (_contentView) {
|
||||
[_contentView removeFromSuperview];
|
||||
}
|
||||
_contentView = contentView;
|
||||
[self addSubview:contentView];
|
||||
}
|
||||
|
||||
- (void)setHeaderView:(UIView *)headerView {
|
||||
if (_headerView) {
|
||||
[_headerView removeFromSuperview];
|
||||
}
|
||||
_headerView = headerView;
|
||||
[self addSubview:headerView];
|
||||
self.refreshable = YES;
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
|
||||
if (-scrollView.contentOffset.y >= self.headerView.height) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
self.refreshing = YES;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
|
||||
if (scrollView.contentOffset.y <= 0) {
|
||||
[self.swipePullingDelegate setPullingDistance:-scrollView.contentOffset.y];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setContentOffset:(CGPoint)contentOffset {
|
||||
[super setContentOffset:contentOffset];
|
||||
}
|
||||
|
||||
- (void)setRefreshing:(BOOL)refreshing {
|
||||
if (_refreshing == refreshing) {
|
||||
return;
|
||||
}
|
||||
if (refreshing) {
|
||||
[self setContentOffset:CGPointMake(0, -self.headerView.height) animated:YES];
|
||||
self.scrollEnabled = NO;
|
||||
if (self.onRefreshBlock) {
|
||||
self.onRefreshBlock();
|
||||
}
|
||||
} else {
|
||||
[self setContentOffset:(CGPoint) {0, 0} animated:YES];
|
||||
self.scrollEnabled = YES;
|
||||
}
|
||||
_refreshing = refreshing;
|
||||
}
|
||||
|
||||
- (void)setRefreshable:(BOOL)refreshable {
|
||||
self.scrollEnabled = refreshable;
|
||||
if (refreshable) {
|
||||
self.contentOffset = (CGPoint) {0, 0};
|
||||
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)refreshable {
|
||||
return self.scrollEnabled;
|
||||
}
|
||||
|
||||
- (void)setContentSize:(CGSize)contentSize {
|
||||
[super setContentSize:contentSize];
|
||||
}
|
||||
@end
|
25
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutItemNode.h
Normal file
25
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutItemNode.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricStackNode.h"
|
||||
|
||||
|
||||
@interface DoricFlowLayoutItemNode : DoricStackNode
|
||||
@end
|
48
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutItemNode.m
Normal file
48
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutItemNode.m
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import "DoricFlowLayoutItemNode.h"
|
||||
|
||||
@interface DoricFlowLayoutItemView : DoricStackView
|
||||
@end
|
||||
|
||||
@implementation DoricFlowLayoutItemView
|
||||
@end
|
||||
|
||||
@interface DoricFlowLayoutItemNode ()
|
||||
@end
|
||||
|
||||
|
||||
@implementation DoricFlowLayoutItemNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
self.reusable = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
self.reusable = YES;
|
||||
}
|
||||
|
||||
- (DoricStackView *)build {
|
||||
return [DoricFlowLayoutItemView new];
|
||||
}
|
||||
@end
|
24
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutNode.h
Normal file
24
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutNode.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
@interface DoricFlowLayoutNode : DoricSuperNode<UICollectionView *>
|
||||
@end
|
322
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutNode.m
Normal file
322
doric-iOS/Pod/Classes/Shader/DoricFlowLayoutNode.m
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/28.
|
||||
//
|
||||
|
||||
#import "DoricFlowLayoutNode.h"
|
||||
#import "DoricFlowLayoutItemNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
|
||||
@protocol DoricFlowLayoutDelegate
|
||||
- (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath;
|
||||
|
||||
- (CGFloat)doricFlowLayoutColumnSpace;
|
||||
|
||||
- (CGFloat)doricFlowLayoutRowSpace;
|
||||
|
||||
- (NSInteger)doricFlowLayoutColumnCount;
|
||||
|
||||
@end
|
||||
|
||||
@interface DoricFlowLayout : UICollectionViewLayout
|
||||
@property(nonatomic, readonly) NSInteger columnCount;
|
||||
@property(nonatomic, readonly) CGFloat columnSpace;
|
||||
@property(nonatomic, readonly) CGFloat rowSpace;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSNumber *> *columnHeightInfo;
|
||||
@property(nonatomic, weak) id <DoricFlowLayoutDelegate> delegate;
|
||||
@end
|
||||
|
||||
@implementation DoricFlowLayout
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_columnHeightInfo = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSInteger)columnCount {
|
||||
return self.delegate.doricFlowLayoutColumnCount ?: 2;
|
||||
}
|
||||
|
||||
- (CGFloat)columnSpace {
|
||||
return self.delegate.doricFlowLayoutColumnSpace ?: 0;
|
||||
}
|
||||
|
||||
- (CGFloat)rowSpace {
|
||||
return self.delegate.doricFlowLayoutRowSpace ?: 0;
|
||||
}
|
||||
|
||||
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)prepareLayout {
|
||||
[super prepareLayout];
|
||||
for (int i = 0; i < self.columnCount; i++) {
|
||||
self.columnHeightInfo[@(i)] = @(0);
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
|
||||
for (int i = 0; i < self.columnCount; i++) {
|
||||
self.columnHeightInfo[@(i)] = @(0);
|
||||
}
|
||||
NSMutableArray *array = [NSMutableArray array];
|
||||
NSInteger count = [self.collectionView numberOfItemsInSection:0];
|
||||
for (int i = 0; i < count; i++) {
|
||||
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
|
||||
[array addObject:attrs];
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSNumber *minYOfColumn = @(0);
|
||||
for (NSNumber *key in self.columnHeightInfo.allKeys) {
|
||||
if ([self.columnHeightInfo[key] floatValue] < [self.columnHeightInfo[minYOfColumn] floatValue]) {
|
||||
minYOfColumn = key;
|
||||
}
|
||||
}
|
||||
|
||||
CGFloat width = (self.collectionView.width - self.columnSpace * (self.columnCount - 1)) / self.columnCount;
|
||||
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
|
||||
CGFloat x = (width + self.columnSpace) * [minYOfColumn integerValue];
|
||||
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
|
||||
if (y > 0) {
|
||||
y += self.rowSpace;
|
||||
}
|
||||
self.columnHeightInfo[minYOfColumn] = @(y + height);
|
||||
|
||||
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
|
||||
attrs.frame = CGRectMake(x, y, width, height);
|
||||
return attrs;
|
||||
}
|
||||
|
||||
- (CGSize)collectionViewContentSize {
|
||||
CGFloat width = self.collectionView.width;
|
||||
CGFloat height = 0;
|
||||
for (NSNumber *column in self.columnHeightInfo.allValues) {
|
||||
height = MAX(height, [column floatValue]);
|
||||
}
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
@end
|
||||
|
||||
@interface DoricFlowLayoutViewCell : UICollectionViewCell
|
||||
@property(nonatomic, strong) DoricFlowLayoutItemNode *viewNode;
|
||||
@end
|
||||
|
||||
@implementation DoricFlowLayoutViewCell
|
||||
@end
|
||||
|
||||
@interface DoricFlowLayoutView : UICollectionView
|
||||
@end
|
||||
|
||||
@implementation DoricFlowLayoutView
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.subviews.count > 0) {
|
||||
CGFloat width = size.width;
|
||||
CGFloat height = size.height;
|
||||
for (UIView *child in self.subviews) {
|
||||
CGSize childSize = [child measureSize:size];
|
||||
width = MAX(childSize.width, width);
|
||||
height = MAX(childSize.height, height);
|
||||
}
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
[super layoutSelf:targetSize];
|
||||
[self reloadData];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewDelegate, DoricFlowLayoutDelegate>
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSValue *> *itemSizeInfo;
|
||||
@property(nonatomic, assign) NSUInteger itemCount;
|
||||
@property(nonatomic, assign) NSUInteger batchCount;
|
||||
@property(nonatomic, assign) NSUInteger columnCount;
|
||||
@property(nonatomic, assign) CGFloat columnSpace;
|
||||
@property(nonatomic, assign) CGFloat rowSpace;
|
||||
@end
|
||||
|
||||
@implementation DoricFlowLayoutNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_itemViewIds = [NSMutableDictionary new];
|
||||
_itemSizeInfo = [NSMutableDictionary new];
|
||||
_batchCount = 15;
|
||||
_columnCount = 2;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UICollectionView *)build {
|
||||
DoricFlowLayout *flowLayout = [[DoricFlowLayout alloc] init];
|
||||
flowLayout.delegate = self;
|
||||
return [[[DoricFlowLayoutView alloc] initWithFrame:CGRectZero
|
||||
collectionViewLayout:flowLayout]
|
||||
also:^(UICollectionView *it) {
|
||||
it.backgroundColor = [UIColor whiteColor];
|
||||
it.pagingEnabled = YES;
|
||||
it.delegate = self;
|
||||
it.dataSource = self;
|
||||
[it registerClass:[DoricFlowLayoutViewCell class] forCellWithReuseIdentifier:@"doricCell"];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"columnSpace" isEqualToString:name]) {
|
||||
self.columnSpace = [prop floatValue];
|
||||
[self.view.collectionViewLayout invalidateLayout];
|
||||
} else if ([@"rowSpace" isEqualToString:name]) {
|
||||
self.rowSpace = [prop floatValue];
|
||||
[self.view.collectionViewLayout invalidateLayout];
|
||||
} else if ([@"columnCount" isEqualToString:name]) {
|
||||
self.columnCount = [prop unsignedIntegerValue];
|
||||
[self.view reloadData];
|
||||
[self.view.collectionViewLayout invalidateLayout];
|
||||
} else if ([@"itemCount" isEqualToString:name]) {
|
||||
self.itemCount = [prop unsignedIntegerValue];
|
||||
[self.view reloadData];
|
||||
} else if ([@"renderItem" isEqualToString:name]) {
|
||||
[self.itemViewIds removeAllObjects];
|
||||
[self clearSubModel];
|
||||
[self.view reloadData];
|
||||
} else if ([@"batchCount" isEqualToString:name]) {
|
||||
self.batchCount = [prop unsignedIntegerValue];
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
||||
NSString *viewId = self.itemViewIds[@(position)];
|
||||
if (viewId && viewId.length > 0) {
|
||||
return [self subModelOf:viewId];
|
||||
} else {
|
||||
DoricAsyncResult *result = [self callJSResponse:@"renderBunchedItems", @(position), @(self.batchCount), nil];
|
||||
JSValue *models = [result waitUntilResult];
|
||||
NSArray *array = [models toArray];
|
||||
[array enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
|
||||
NSString *thisViewId = obj[@"id"];
|
||||
[self setSubModel:obj in:thisViewId];
|
||||
NSUInteger pos = position + idx;
|
||||
self.itemViewIds[@(pos)] = thisViewId;
|
||||
}];
|
||||
return array[0];
|
||||
}
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
__block DoricViewNode *ret = nil;
|
||||
[self.doricContext.driver ensureSyncInMainQueue:^{
|
||||
for (UICollectionViewCell *collectionViewCell in self.view.visibleCells) {
|
||||
if ([collectionViewCell isKindOfClass:[DoricFlowLayoutViewCell class]]) {
|
||||
DoricFlowLayoutItemNode *node = ((DoricFlowLayoutViewCell *) collectionViewCell).viewNode;
|
||||
if ([viewId isEqualToString:node.viewId]) {
|
||||
ret = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
NSString *viewId = subModel[@"id"];
|
||||
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
|
||||
if (viewNode) {
|
||||
[viewNode blend:subModel[@"props"]];
|
||||
} else {
|
||||
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
|
||||
[self recursiveMixin:subModel to:model];
|
||||
[self setSubModel:model in:viewId];
|
||||
}
|
||||
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
|
||||
if ([viewId isEqualToString:obj]) {
|
||||
*stop = YES;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.view reloadItemsAtIndexPaths:@[indexPath]];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)callItem:(NSUInteger)position size:(CGSize)size {
|
||||
NSValue *old = self.itemSizeInfo[@(position)];
|
||||
if (old && CGSizeEqualToSize([old CGSizeValue], size)) {
|
||||
return;
|
||||
}
|
||||
self.itemSizeInfo[@(position)] = [NSValue valueWithCGSize:size];
|
||||
[self.view.collectionViewLayout invalidateLayout];
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.itemCount;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSUInteger position = (NSUInteger) indexPath.row;
|
||||
NSDictionary *model = [self itemModelAt:position];
|
||||
NSDictionary *props = model[@"props"];
|
||||
DoricFlowLayoutViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"doricCell" forIndexPath:indexPath];
|
||||
if (!cell.viewNode) {
|
||||
DoricFlowLayoutItemNode *itemNode = [[DoricFlowLayoutItemNode alloc] initWithContext:self.doricContext];
|
||||
[itemNode initWithSuperNode:self];
|
||||
cell.viewNode = itemNode;
|
||||
[cell.contentView addSubview:itemNode.view];
|
||||
}
|
||||
DoricFlowLayoutItemNode *node = cell.viewNode;
|
||||
node.viewId = model[@"id"];
|
||||
[node blend:props];
|
||||
CGFloat width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
|
||||
CGSize size = [node.view measureSize:CGSizeMake(width, collectionView.height)];
|
||||
[node.view layoutSelf:size];
|
||||
[self callItem:position size:size];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSUInteger position = (NSUInteger) indexPath.row;
|
||||
NSValue *value = self.itemSizeInfo[@(position)];
|
||||
if (value) {
|
||||
return [value CGSizeValue].height;
|
||||
} else {
|
||||
return 100;
|
||||
}
|
||||
}
|
||||
|
||||
- (CGFloat)doricFlowLayoutColumnSpace {
|
||||
return self.columnSpace;
|
||||
}
|
||||
|
||||
- (CGFloat)doricFlowLayoutRowSpace {
|
||||
return self.rowSpace;
|
||||
}
|
||||
|
||||
- (NSInteger)doricFlowLayoutColumnCount {
|
||||
return self.columnCount;
|
||||
}
|
||||
|
||||
@end
|
30
doric-iOS/Pod/Classes/Shader/DoricGroupNode.h
Normal file
30
doric-iOS/Pod/Classes/Shader/DoricGroupNode.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricGroupNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricGroupNode <V:UIView *> : DoricSuperNode<V>
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
171
doric-iOS/Pod/Classes/Shader/DoricGroupNode.m
Normal file
171
doric-iOS/Pod/Classes/Shader/DoricGroupNode.m
Normal file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricGroupNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import <Doric/DoricExtensions.h>
|
||||
#import "DoricGroupNode.h"
|
||||
|
||||
@interface DoricGroupNode ()
|
||||
@property(nonatomic, copy) NSArray<DoricViewNode *> *childNodes;
|
||||
@property(nonatomic, copy) NSArray <NSString *> *childViewIds;
|
||||
@end
|
||||
|
||||
@implementation DoricGroupNode
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_childNodes = @[];
|
||||
_childViewIds = @[];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView *)build {
|
||||
UIView *ret = [[UIView alloc] init];
|
||||
ret.clipsToBounds = YES;
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"children" isEqualToString:name]) {
|
||||
self.childViewIds = prop;
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
[self configChildNodes];
|
||||
}
|
||||
|
||||
- (DoricLayoutConfig *)generateDefaultLayoutParams {
|
||||
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init];
|
||||
return params;
|
||||
}
|
||||
|
||||
- (void)configChildNodes {
|
||||
NSMutableArray *childNodes = [self.childNodes mutableCopy];
|
||||
for (NSUInteger idx = 0; idx < self.childViewIds.count; idx++) {
|
||||
NSString *viewId = self.childViewIds[idx];
|
||||
NSDictionary *model = [self subModelOf:viewId];
|
||||
NSString *type = model[@"type"];
|
||||
if (idx < self.childNodes.count) {
|
||||
DoricViewNode *oldNode = childNodes[idx];
|
||||
if ([viewId isEqualToString:oldNode.viewId]) {
|
||||
///Same,skip
|
||||
} else {
|
||||
if (self.reusable) {
|
||||
if ([oldNode.type isEqualToString:type]) {
|
||||
///Same type,can be reused
|
||||
oldNode.viewId = viewId;
|
||||
[oldNode blend:model[@"props"]];
|
||||
} else {
|
||||
///Replace this view
|
||||
[childNodes removeObjectAtIndex:idx];
|
||||
[oldNode.view removeFromSuperview];
|
||||
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
|
||||
if ([viewNode isKindOfClass:[DoricGroupNode class]]) {
|
||||
((DoricGroupNode *) viewNode).reusable = self.reusable;
|
||||
}
|
||||
viewNode.viewId = viewId;
|
||||
[viewNode initWithSuperNode:self];
|
||||
[viewNode blend:model[@"props"]];
|
||||
[childNodes insertObject:viewNode atIndex:idx];
|
||||
[self.view insertSubview:viewNode.view atIndex:idx];
|
||||
}
|
||||
} else {
|
||||
///Find in remain nodes
|
||||
NSInteger position = -1;
|
||||
for (NSUInteger start = idx + 1; start < childNodes.count; start++) {
|
||||
DoricViewNode *node = childNodes[start];
|
||||
if ([viewId isEqualToString:node.viewId]) {
|
||||
position = start;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (position >= 0) {
|
||||
///Found ,swap idx,position
|
||||
DoricViewNode *reused = childNodes[(NSUInteger) position];
|
||||
[childNodes removeObjectAtIndex:(NSUInteger) position];
|
||||
[childNodes removeObjectAtIndex:idx];
|
||||
[childNodes insertObject:reused atIndex:idx];
|
||||
[childNodes insertObject:oldNode atIndex:(NSUInteger) position];
|
||||
|
||||
///View swap index
|
||||
[reused.view removeFromSuperview];
|
||||
[oldNode.view removeFromSuperview];
|
||||
[self.view insertSubview:reused.view atIndex:idx];
|
||||
[self.view insertSubview:oldNode.view atIndex:position];
|
||||
} else {
|
||||
///Not found,insert
|
||||
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
|
||||
viewNode.viewId = viewId;
|
||||
[viewNode initWithSuperNode:self];
|
||||
[viewNode blend:model[@"props"]];
|
||||
[childNodes insertObject:viewNode atIndex:idx];
|
||||
[self.view insertSubview:viewNode.view atIndex:idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/// Insert
|
||||
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
|
||||
if ([viewNode isKindOfClass:[DoricGroupNode class]]) {
|
||||
((DoricGroupNode *) viewNode).reusable = self.reusable;
|
||||
}
|
||||
viewNode.viewId = viewId;
|
||||
[viewNode initWithSuperNode:self];
|
||||
[viewNode blend:model[@"props"]];
|
||||
[childNodes addObject:viewNode];
|
||||
[self.view addSubview:viewNode.view];
|
||||
}
|
||||
}
|
||||
|
||||
NSUInteger count = childNodes.count;
|
||||
for (NSUInteger idx = self.childViewIds.count; idx < count; idx++) {
|
||||
DoricViewNode *viewNode = childNodes.lastObject;
|
||||
[childNodes removeLastObject];
|
||||
[viewNode.view removeFromSuperview];
|
||||
}
|
||||
self.childNodes = [childNodes copy];
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
NSString *viewId = subModel[@"id"];
|
||||
[self.childNodes enumerateObjectsUsingBlock:^(DoricViewNode *obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([viewId isEqualToString:obj.viewId]) {
|
||||
[obj blend:subModel[@"props"]];
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
for (DoricViewNode *viewNode in self.childNodes) {
|
||||
if ([viewId isEqualToString:viewNode.viewId]) {
|
||||
return viewNode;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
@end
|
26
doric-iOS/Pod/Classes/Shader/DoricHLayoutNode.h
Normal file
26
doric-iOS/Pod/Classes/Shader/DoricHLayoutNode.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricHLayoutNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricGroupNode.h"
|
||||
|
||||
@interface DoricHLayoutNode : DoricGroupNode<DoricHLayoutView *>
|
||||
@end
|
40
doric-iOS/Pod/Classes/Shader/DoricHLayoutNode.m
Normal file
40
doric-iOS/Pod/Classes/Shader/DoricHLayoutNode.m
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricHLayoutNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricHLayoutNode.h"
|
||||
#import "DoricUtil.h"
|
||||
|
||||
@implementation DoricHLayoutNode
|
||||
- (DoricHLayoutView *)build {
|
||||
return [DoricHLayoutView new];
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricHLayoutView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([name isEqualToString:@"gravity"]) {
|
||||
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||
} else if ([name isEqualToString:@"space"]) {
|
||||
view.space = [(NSNumber *) prop floatValue];
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
@end
|
31
doric-iOS/Pod/Classes/Shader/DoricImageNode.h
Normal file
31
doric-iOS/Pod/Classes/Shader/DoricImageNode.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricImageNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/6.
|
||||
//
|
||||
|
||||
#import "DoricViewNode.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricImageNode : DoricViewNode<UIImageView *>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
87
doric-iOS/Pod/Classes/Shader/DoricImageNode.m
Normal file
87
doric-iOS/Pod/Classes/Shader/DoricImageNode.m
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricImageNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/8/6.
|
||||
//
|
||||
|
||||
#import "DoricImageNode.h"
|
||||
#import "Doric.h"
|
||||
#import "YYWebImage.h"
|
||||
|
||||
@interface DoricImageNode ()
|
||||
@property(nonatomic, copy) NSString *loadCallbackId;
|
||||
@end
|
||||
|
||||
@implementation DoricImageNode
|
||||
|
||||
- (UIImageView *)build {
|
||||
return [[YYAnimatedImageView new] also:^(UIImageView *it) {
|
||||
it.clipsToBounds = YES;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(UIImageView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"imageUrl" isEqualToString:name]) {
|
||||
__weak typeof(self) _self = self;
|
||||
[view yy_setImageWithURL:[NSURL URLWithString:prop] placeholder:nil options:0 completion:^(UIImage *image, NSURL *url, YYWebImageFromType from, YYWebImageStage stage, NSError *error) {
|
||||
__strong typeof(_self) self = _self;
|
||||
if (error) {
|
||||
if (self.loadCallbackId.length > 0) {
|
||||
[self callJSResponse:self.loadCallbackId, nil];
|
||||
}
|
||||
} else {
|
||||
if (self.loadCallbackId.length > 0) {
|
||||
[self callJSResponse:self.loadCallbackId,
|
||||
@{@"width": @(image.size.width), @"height": @(image.size.height)},
|
||||
nil];
|
||||
}
|
||||
[self requestLayout];
|
||||
}
|
||||
}];
|
||||
} else if ([@"scaleType" isEqualToString:name]) {
|
||||
switch ([prop integerValue]) {
|
||||
case 1: {
|
||||
self.view.contentMode = UIViewContentModeScaleAspectFit;
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
self.view.contentMode = UIViewContentModeScaleAspectFill;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
self.view.contentMode = UIViewContentModeScaleToFill;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if ([@"loadCallback" isEqualToString:name]) {
|
||||
self.loadCallbackId = prop;
|
||||
} else if ([@"imageBase64" isEqualToString:name]) {
|
||||
NSString *base64 = prop;
|
||||
if (YES == [base64 hasPrefix:@"data:image"]) {
|
||||
base64 = [base64 componentsSeparatedByString:@","].lastObject;
|
||||
}
|
||||
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:base64
|
||||
options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
||||
UIImage *image = [UIImage imageWithData:imageData];
|
||||
self.view.image = image;
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
@end
|
99
doric-iOS/Pod/Classes/Shader/DoricLayouts.h
Normal file
99
doric-iOS/Pod/Classes/Shader/DoricLayouts.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/10/23.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
typedef UIEdgeInsets DoricMargin;
|
||||
|
||||
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom);
|
||||
|
||||
typedef NS_ENUM(NSInteger, DoricLayoutSpec) {
|
||||
DoricLayoutExact = 0,
|
||||
DoricLayoutWrapContent = 1,
|
||||
DoricLayoutAtMost = 2,
|
||||
};
|
||||
|
||||
typedef NS_ENUM(NSInteger, DoricGravity) {
|
||||
SPECIFIED = 1,
|
||||
START = 1 << 1,
|
||||
END = 1 << 2,
|
||||
SHIFT_X = 0,
|
||||
SHIFT_Y = 4,
|
||||
LEFT = (START | SPECIFIED) << SHIFT_X,
|
||||
RIGHT = (END | SPECIFIED) << SHIFT_X,
|
||||
TOP = (START | SPECIFIED) << SHIFT_Y,
|
||||
BOTTOM = (END | SPECIFIED) << SHIFT_Y,
|
||||
CENTER_X = SPECIFIED << SHIFT_X,
|
||||
CENTER_Y = SPECIFIED << SHIFT_Y,
|
||||
CENTER = CENTER_X | CENTER_Y,
|
||||
};
|
||||
|
||||
@interface DoricLayoutConfig : NSObject
|
||||
@property(nonatomic, assign) DoricLayoutSpec widthSpec;
|
||||
@property(nonatomic, assign) DoricLayoutSpec heightSpec;
|
||||
@property(nonatomic) DoricMargin margin;
|
||||
@property(nonatomic, assign) DoricGravity alignment;
|
||||
@property(nonatomic, assign) NSUInteger weight;
|
||||
|
||||
- (instancetype)init;
|
||||
|
||||
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height;
|
||||
|
||||
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface DoricLayoutContainer : UIView
|
||||
@end
|
||||
|
||||
@interface DoricStackView : DoricLayoutContainer
|
||||
@end
|
||||
|
||||
@interface DoricLinearView : DoricLayoutContainer
|
||||
@property(nonatomic, assign) DoricGravity gravity;
|
||||
@property(nonatomic, assign) CGFloat space;
|
||||
@end
|
||||
|
||||
|
||||
@interface DoricVLayoutView : DoricLinearView
|
||||
@end
|
||||
|
||||
@interface DoricHLayoutView : DoricLinearView
|
||||
@end
|
||||
|
||||
@interface UIView (DoricLayoutConfig)
|
||||
@property(nonatomic, strong) DoricLayoutConfig *layoutConfig;
|
||||
@end
|
||||
|
||||
@interface UIView (DoricTag)
|
||||
@property(nonatomic, copy) NSString *tagString;
|
||||
|
||||
- (UIView *)viewWithTagString:(NSString *)tagString;
|
||||
@end
|
||||
|
||||
@interface UIView (DoricLayouts)
|
||||
- (void)layoutSelf:(CGSize)targetSize;
|
||||
|
||||
- (CGSize)measureSize:(CGSize)targetSize;
|
||||
|
||||
- (void)doricLayoutSubviews;
|
||||
|
||||
- (BOOL)requestFromSubview:(UIView *)subview;
|
||||
@end
|
457
doric-iOS/Pod/Classes/Shader/DoricLayouts.m
Normal file
457
doric-iOS/Pod/Classes/Shader/DoricLayouts.m
Normal file
@@ -0,0 +1,457 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/10/23.
|
||||
//
|
||||
|
||||
#import "DoricLayouts.h"
|
||||
#import <objc/runtime.h>
|
||||
#import <Doric/DoricLayouts.h>
|
||||
#import "UIView+Doric.h"
|
||||
|
||||
static const void *kLayoutConfig = &kLayoutConfig;
|
||||
|
||||
@implementation UIView (DoricLayoutConfig)
|
||||
@dynamic layoutConfig;
|
||||
|
||||
- (void)setLayoutConfig:(DoricLayoutConfig *)layoutConfig {
|
||||
objc_setAssociatedObject(self, kLayoutConfig, layoutConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
|
||||
- (DoricLayoutConfig *)layoutConfig {
|
||||
return objc_getAssociatedObject(self, kLayoutConfig);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
static const void *kTagString = &kTagString;
|
||||
|
||||
@implementation UIView (DoricTag)
|
||||
|
||||
- (void)setTagString:(NSString *)tagString {
|
||||
objc_setAssociatedObject(self, kTagString, tagString, OBJC_ASSOCIATION_COPY_NONATOMIC);
|
||||
self.tag = [tagString hash];
|
||||
}
|
||||
|
||||
- (NSString *)tagString {
|
||||
return objc_getAssociatedObject(self, kTagString);
|
||||
}
|
||||
|
||||
|
||||
- (UIView *)viewWithTagString:(NSString *)tagString {
|
||||
// notice the potential hash collision
|
||||
return [self viewWithTag:[tagString hash]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation UIView (DoricLayouts)
|
||||
/**
|
||||
* Measure self's size
|
||||
* */
|
||||
- (CGSize)measureSize:(CGSize)targetSize {
|
||||
CGFloat width = self.width;
|
||||
CGFloat height = self.height;
|
||||
|
||||
DoricLayoutConfig *config = self.layoutConfig;
|
||||
if (!config) {
|
||||
config = [DoricLayoutConfig new];
|
||||
}
|
||||
if (config.widthSpec == DoricLayoutAtMost
|
||||
|| config.widthSpec == DoricLayoutWrapContent) {
|
||||
width = targetSize.width - config.margin.left - config.margin.right;
|
||||
}
|
||||
if (config.heightSpec == DoricLayoutAtMost
|
||||
|| config.heightSpec == DoricLayoutWrapContent) {
|
||||
height = targetSize.height - config.margin.top - config.margin.bottom;
|
||||
}
|
||||
|
||||
CGSize contentSize = [self sizeThatFits:CGSizeMake(width, height)];
|
||||
if (config.widthSpec == DoricLayoutWrapContent) {
|
||||
width = contentSize.width;
|
||||
}
|
||||
if (config.heightSpec == DoricLayoutWrapContent) {
|
||||
height = contentSize.height;
|
||||
}
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
|
||||
/**
|
||||
* layout self and subviews
|
||||
* */
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
self.width = targetSize.width;
|
||||
self.height = targetSize.height;
|
||||
for (UIView *view in self.subviews) {
|
||||
[view layoutSelf:[view measureSize:targetSize]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)doricLayoutSubviews {
|
||||
if ([self.superview requestFromSubview:self]) {
|
||||
[self.superview doricLayoutSubviews];
|
||||
} else {
|
||||
[self layoutSelf:CGSizeMake(self.width, self.height)];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)requestFromSubview:(UIView *)subview {
|
||||
if (self.layoutConfig
|
||||
&& self.layoutConfig.widthSpec != DoricLayoutExact
|
||||
&& self.layoutConfig.heightSpec != DoricLayoutExact) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
DoricMargin DoricMarginMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) {
|
||||
DoricMargin margin;
|
||||
margin.left = left;
|
||||
margin.top = top;
|
||||
margin.right = right;
|
||||
margin.bottom = bottom;
|
||||
return margin;
|
||||
}
|
||||
|
||||
@implementation DoricLayoutConfig
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_widthSpec = DoricLayoutExact;
|
||||
_heightSpec = DoricLayoutExact;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height {
|
||||
if (self = [super init]) {
|
||||
_widthSpec = width;
|
||||
_heightSpec = height;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (instancetype)initWithWidth:(DoricLayoutSpec)width height:(DoricLayoutSpec)height margin:(DoricMargin)margin {
|
||||
if (self = [super init]) {
|
||||
_widthSpec = width;
|
||||
_heightSpec = height;
|
||||
_margin = margin;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface DoricLayoutContainer ()
|
||||
@property(nonatomic, assign) CGFloat contentWidth;
|
||||
@property(nonatomic, assign) CGFloat contentHeight;
|
||||
@property(nonatomic, assign) NSUInteger contentWeight;
|
||||
@end
|
||||
|
||||
@implementation DoricLayoutContainer
|
||||
- (void)setNeedsLayout {
|
||||
[super setNeedsLayout];
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
[self doricLayoutSubviews];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface DoricStackView ()
|
||||
@end
|
||||
|
||||
@implementation DoricStackView
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
CGFloat contentWidth = 0;
|
||||
CGFloat contentHeight = 0;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
CGSize childSize;
|
||||
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
childSize = [child measureSize:CGSizeMake(size.width, size.height)];
|
||||
} else {
|
||||
childSize = child.bounds.size;
|
||||
}
|
||||
contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right);
|
||||
contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom);
|
||||
}
|
||||
self.contentWidth = contentWidth;
|
||||
self.contentHeight = contentHeight;
|
||||
return CGSizeMake(contentWidth, contentHeight);
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
self.width = targetSize.width;
|
||||
self.height = targetSize.height;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height)];
|
||||
[child layoutSelf:size];
|
||||
DoricGravity gravity = childConfig.alignment;
|
||||
if ((gravity & LEFT) == LEFT) {
|
||||
child.left = 0;
|
||||
} else if ((gravity & RIGHT) == RIGHT) {
|
||||
child.right = targetSize.width;
|
||||
} else if ((gravity & CENTER_X) == CENTER_X) {
|
||||
child.centerX = targetSize.width / 2;
|
||||
} else {
|
||||
if (childConfig.margin.left) {
|
||||
child.left = childConfig.margin.left;
|
||||
} else if (childConfig.margin.right) {
|
||||
child.right = targetSize.width - childConfig.margin.right;
|
||||
}
|
||||
}
|
||||
if ((gravity & TOP) == TOP) {
|
||||
child.top = 0;
|
||||
} else if ((gravity & BOTTOM) == BOTTOM) {
|
||||
child.bottom = targetSize.height;
|
||||
} else if ((gravity & CENTER_Y) == CENTER_Y) {
|
||||
child.centerY = targetSize.height / 2;
|
||||
} else {
|
||||
if (childConfig.margin.top) {
|
||||
child.top = childConfig.margin.top;
|
||||
} else if (childConfig.margin.bottom) {
|
||||
child.bottom = targetSize.height - childConfig.margin.bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DoricLinearView
|
||||
@end
|
||||
|
||||
@implementation DoricVLayoutView
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
CGFloat contentWidth = 0;
|
||||
CGFloat contentHeight = 0;
|
||||
NSUInteger contentWeight = 0;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
CGSize childSize;
|
||||
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
childSize = [child measureSize:CGSizeMake(size.width, size.height - contentHeight)];
|
||||
} else {
|
||||
childSize = child.bounds.size;
|
||||
}
|
||||
contentWidth = MAX(contentWidth, childSize.width + childConfig.margin.left + childConfig.margin.right);
|
||||
contentHeight += childSize.height + self.space + childConfig.margin.top + childConfig.margin.bottom;
|
||||
contentWeight += childConfig.weight;
|
||||
}
|
||||
contentHeight -= self.space;
|
||||
self.contentWidth = contentWidth;
|
||||
self.contentHeight = contentHeight;
|
||||
self.contentWeight = contentWeight;
|
||||
if (contentWeight) {
|
||||
contentHeight = size.height;
|
||||
}
|
||||
return CGSizeMake(contentWidth, contentHeight);
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
self.width = targetSize.width;
|
||||
self.height = targetSize.height;
|
||||
CGFloat yStart = 0;
|
||||
if ((self.gravity & TOP) == TOP) {
|
||||
yStart = 0;
|
||||
} else if ((self.gravity & BOTTOM) == BOTTOM) {
|
||||
yStart = targetSize.height - self.contentHeight;
|
||||
} else if ((self.gravity & CENTER_Y) == CENTER_Y) {
|
||||
yStart = (targetSize.height - self.contentHeight) / 2;
|
||||
}
|
||||
CGFloat remain = targetSize.height - self.contentHeight;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
|
||||
CGSize size = [child measureSize:CGSizeMake(targetSize.width, targetSize.height - yStart)];
|
||||
if (childConfig.weight) {
|
||||
size.height += remain / self.contentWeight * childConfig.weight;
|
||||
}
|
||||
[child layoutSelf:size];
|
||||
DoricGravity gravity = childConfig.alignment | self.gravity;
|
||||
if ((gravity & LEFT) == LEFT) {
|
||||
child.left = 0;
|
||||
} else if ((gravity & RIGHT) == RIGHT) {
|
||||
child.right = self.width;
|
||||
} else if ((gravity & CENTER_X) == CENTER_X) {
|
||||
child.centerX = targetSize.width / 2;
|
||||
} else {
|
||||
if (childConfig.margin.left) {
|
||||
child.left = childConfig.margin.left;
|
||||
} else if (childConfig.margin.right) {
|
||||
child.right = targetSize.width - childConfig.margin.right;
|
||||
}
|
||||
}
|
||||
if (childConfig.margin.top) {
|
||||
yStart += childConfig.margin.top;
|
||||
}
|
||||
child.top = yStart;
|
||||
yStart = child.bottom + self.space;
|
||||
if (childConfig.margin.bottom) {
|
||||
yStart += childConfig.margin.bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DoricHLayoutView
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
CGFloat contentWidth = 0;
|
||||
CGFloat contentHeight = 0;
|
||||
NSUInteger contentWeight = 0;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
CGSize childSize;
|
||||
if (CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
childSize = [child measureSize:CGSizeMake(size.width - contentWidth, size.height)];
|
||||
} else {
|
||||
childSize = child.bounds.size;
|
||||
}
|
||||
contentWidth += childSize.width + self.space + childConfig.margin.left + childConfig.margin.right;
|
||||
contentHeight = MAX(contentHeight, childSize.height + childConfig.margin.top + childConfig.margin.bottom);
|
||||
contentWeight += childConfig.weight;
|
||||
}
|
||||
contentWidth -= self.space;
|
||||
self.contentWidth = contentWidth;
|
||||
self.contentHeight = contentHeight;
|
||||
self.contentWeight = contentWeight;
|
||||
if (contentWeight) {
|
||||
contentWidth = size.width;
|
||||
}
|
||||
return CGSizeMake(contentWidth, contentHeight);
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
self.width = targetSize.width;
|
||||
self.height = targetSize.height;
|
||||
CGFloat xStart = 0;
|
||||
if (self.contentWeight) {
|
||||
xStart = 0;
|
||||
} else if ((self.gravity & LEFT) == LEFT) {
|
||||
xStart = 0;
|
||||
} else if ((self.gravity & RIGHT) == RIGHT) {
|
||||
xStart = targetSize.width - self.contentWidth;
|
||||
} else if ((self.gravity & CENTER_X) == CENTER_X) {
|
||||
xStart = (targetSize.width - self.contentWidth) / 2;
|
||||
}
|
||||
CGFloat remain = targetSize.width - self.contentWidth;
|
||||
for (UIView *child in self.subviews) {
|
||||
if (child.isHidden) {
|
||||
continue;
|
||||
}
|
||||
if (!CGAffineTransformEqualToTransform(child.transform, CGAffineTransformIdentity)) {
|
||||
continue;
|
||||
}
|
||||
DoricLayoutConfig *childConfig = child.layoutConfig;
|
||||
if (!childConfig) {
|
||||
childConfig = [DoricLayoutConfig new];
|
||||
}
|
||||
|
||||
CGSize size = [child measureSize:CGSizeMake(targetSize.width - xStart, targetSize.height)];
|
||||
if (childConfig.weight) {
|
||||
size.width += remain / self.contentWeight * childConfig.weight;
|
||||
}
|
||||
|
||||
[child layoutSelf:size];
|
||||
|
||||
DoricGravity gravity = childConfig.alignment | self.gravity;
|
||||
if ((gravity & TOP) == TOP) {
|
||||
child.top = 0;
|
||||
} else if ((gravity & BOTTOM) == BOTTOM) {
|
||||
child.bottom = targetSize.height;
|
||||
} else if ((gravity & CENTER_Y) == CENTER_Y) {
|
||||
child.centerY = targetSize.height / 2;
|
||||
} else {
|
||||
if (childConfig.margin.top) {
|
||||
child.top = childConfig.margin.top;
|
||||
} else if (childConfig.margin.bottom) {
|
||||
child.bottom = targetSize.height - childConfig.margin.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
if (childConfig.margin.left) {
|
||||
xStart += childConfig.margin.left;
|
||||
}
|
||||
child.left = xStart;
|
||||
xStart = child.right + self.space;
|
||||
if (childConfig.margin.right) {
|
||||
xStart += childConfig.margin.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
DoricVLayoutView *vLayout(NSArray <__kindof UIView *> *views) {
|
||||
DoricVLayoutView *layout = [[DoricVLayoutView alloc] initWithFrame:CGRectZero];
|
||||
for (__kindof UIView *uiView in views) {
|
||||
[layout addSubview:uiView];
|
||||
}
|
||||
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||
return layout;
|
||||
}
|
||||
|
||||
DoricHLayoutView *hLayout(NSArray <__kindof UIView *> *views) {
|
||||
DoricHLayoutView *layout = [[DoricHLayoutView alloc] initWithFrame:CGRectZero];
|
||||
for (__kindof UIView *uiView in views) {
|
||||
[layout addSubview:uiView];
|
||||
}
|
||||
layout.layoutConfig = [[DoricLayoutConfig alloc] initWithWidth:DoricLayoutWrapContent height:DoricLayoutWrapContent];
|
||||
return layout;
|
||||
}
|
25
doric-iOS/Pod/Classes/Shader/DoricListItemNode.h
Normal file
25
doric-iOS/Pod/Classes/Shader/DoricListItemNode.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricStackNode.h"
|
||||
|
||||
@interface DoricListItemNode : DoricStackNode
|
||||
@end
|
49
doric-iOS/Pod/Classes/Shader/DoricListItemNode.m
Normal file
49
doric-iOS/Pod/Classes/Shader/DoricListItemNode.m
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import "DoricListItemNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
|
||||
@interface DoricListItemNode ()
|
||||
@end
|
||||
|
||||
@interface DoricListItemView : DoricStackView
|
||||
@end
|
||||
|
||||
@implementation DoricListItemView
|
||||
@end
|
||||
|
||||
|
||||
@implementation DoricListItemNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
self.reusable = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
self.reusable = YES;
|
||||
}
|
||||
|
||||
- (DoricStackView *)build {
|
||||
return [DoricListItemView new];
|
||||
}
|
||||
@end
|
24
doric-iOS/Pod/Classes/Shader/DoricListNode.h
Normal file
24
doric-iOS/Pod/Classes/Shader/DoricListNode.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
@interface DoricListNode : DoricSuperNode<UITableView *>
|
||||
@end
|
216
doric-iOS/Pod/Classes/Shader/DoricListNode.m
Normal file
216
doric-iOS/Pod/Classes/Shader/DoricListNode.m
Normal file
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import "DoricListNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricListItemNode.h"
|
||||
#import "DoricLayouts.h"
|
||||
#import "DoricRefreshableNode.h"
|
||||
|
||||
@interface DoricTableViewCell : UITableViewCell
|
||||
@property(nonatomic, strong) DoricListItemNode *doricListItemNode;
|
||||
@end
|
||||
|
||||
@implementation DoricTableViewCell
|
||||
@end
|
||||
|
||||
@interface DoricTableView : UITableView
|
||||
@end
|
||||
|
||||
@implementation DoricTableView
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.subviews.count > 0) {
|
||||
CGFloat width = size.width;
|
||||
CGFloat height = 0;
|
||||
|
||||
for (UIView *child in self.subviews) {
|
||||
CGSize childSize = [child measureSize:size];
|
||||
width = MAX(childSize.width, width);
|
||||
height += childSize.height;
|
||||
}
|
||||
return CGSizeMake(width, MAX(height, size.height));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
[super layoutSelf:targetSize];
|
||||
[self reloadData];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@interface DoricListNode () <UITableViewDataSource, UITableViewDelegate>
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSNumber *> *itemHeights;
|
||||
@property(nonatomic, assign) NSUInteger itemCount;
|
||||
@property(nonatomic, assign) NSUInteger batchCount;
|
||||
@end
|
||||
|
||||
@implementation DoricListNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_itemViewIds = [NSMutableDictionary new];
|
||||
_itemHeights = [NSMutableDictionary new];
|
||||
_batchCount = 15;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
if ([superNode isKindOfClass:[DoricRefreshableNode class]]) {
|
||||
self.view.bounces = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (UITableView *)build {
|
||||
return [[DoricTableView new] also:^(UITableView *it) {
|
||||
it.dataSource = self;
|
||||
it.delegate = self;
|
||||
it.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(UITableView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"itemCount" isEqualToString:name]) {
|
||||
self.itemCount = [prop unsignedIntegerValue];
|
||||
[self.view reloadData];
|
||||
} else if ([@"renderItem" isEqualToString:name]) {
|
||||
[self.itemViewIds removeAllObjects];
|
||||
[self clearSubModel];
|
||||
[self.view reloadData];
|
||||
} else if ([@"batchCount" isEqualToString:name]) {
|
||||
self.batchCount = [prop unsignedIntegerValue];
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return self.itemCount;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSUInteger position = (NSUInteger) indexPath.row;
|
||||
NSDictionary *model = [self itemModelAt:position];
|
||||
NSDictionary *props = model[@"props"];
|
||||
NSString *reuseId = props[@"identifier"];
|
||||
|
||||
DoricTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseId ?: @"doriccell"];
|
||||
if (!cell) {
|
||||
cell = [[DoricTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseId ?: @"doriccell"];
|
||||
DoricListItemNode *listItemNode = [[DoricListItemNode alloc] initWithContext:self.doricContext];
|
||||
[listItemNode initWithSuperNode:self];
|
||||
cell.doricListItemNode = listItemNode;
|
||||
[cell.contentView addSubview:listItemNode.view];
|
||||
}
|
||||
DoricListItemNode *node = cell.doricListItemNode;
|
||||
node.viewId = model[@"id"];
|
||||
[node blend:props];
|
||||
CGSize size = [node.view measureSize:CGSizeMake(tableView.width, tableView.height)];
|
||||
[node.view layoutSelf:size];
|
||||
[self callItem:position height:size.height];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSUInteger position = (NSUInteger) indexPath.row;
|
||||
NSNumber *heightNumber = self.itemHeights[@(position)];
|
||||
if (heightNumber) {
|
||||
return [heightNumber floatValue];
|
||||
} else {
|
||||
return 44.f;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
||||
NSString *viewId = self.itemViewIds[@(position)];
|
||||
if (viewId && viewId.length > 0) {
|
||||
return [self subModelOf:viewId];
|
||||
} else {
|
||||
DoricAsyncResult *result = [self callJSResponse:@"renderBunchedItems", @(position), @(self.batchCount), nil];
|
||||
JSValue *models = [result waitUntilResult];
|
||||
NSArray *array = [models toArray];
|
||||
[array enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
|
||||
NSString *thisViewId = obj[@"id"];
|
||||
[self setSubModel:obj in:thisViewId];
|
||||
NSUInteger pos = position + idx;
|
||||
self.itemViewIds[@(pos)] = thisViewId;
|
||||
}];
|
||||
return array[0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
NSString *viewId = subModel[@"id"];
|
||||
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
|
||||
if (viewNode) {
|
||||
[viewNode blend:subModel[@"props"]];
|
||||
} else {
|
||||
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
|
||||
[self recursiveMixin:subModel to:model];
|
||||
[self setSubModel:model in:viewId];
|
||||
}
|
||||
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
|
||||
if ([viewId isEqualToString:obj]) {
|
||||
*stop = YES;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.view reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)callItem:(NSUInteger)position height:(CGFloat)height {
|
||||
NSNumber *old = self.itemHeights[@(position)];
|
||||
if (old && old.floatValue == height) {
|
||||
return;
|
||||
}
|
||||
self.itemHeights[@(position)] = @(height);
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:position inSection:0];
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.view reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}];
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
__block DoricViewNode *ret = nil;
|
||||
[self.doricContext.driver ensureSyncInMainQueue:^{
|
||||
for (UITableViewCell *tableViewCell in self.view.visibleCells) {
|
||||
if ([tableViewCell isKindOfClass:[DoricTableViewCell class]]) {
|
||||
DoricListItemNode *node = ((DoricTableViewCell *) tableViewCell).doricListItemNode;
|
||||
if ([viewId isEqualToString:node.viewId]) {
|
||||
ret = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
33
doric-iOS/Pod/Classes/Shader/DoricRootNode.h
Normal file
33
doric-iOS/Pod/Classes/Shader/DoricRootNode.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricRootNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricStackNode.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricRootNode : DoricStackNode
|
||||
|
||||
- (void)setupRootView:(DoricStackView *)view;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
33
doric-iOS/Pod/Classes/Shader/DoricRootNode.m
Normal file
33
doric-iOS/Pod/Classes/Shader/DoricRootNode.m
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricRootNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricRootNode.h"
|
||||
|
||||
@implementation DoricRootNode
|
||||
- (void)setupRootView:(DoricStackView *)view {
|
||||
self.view = view;
|
||||
}
|
||||
|
||||
- (void)requestLayout {
|
||||
[self.view setNeedsLayout];
|
||||
}
|
||||
@end
|
30
doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h
Normal file
30
doric-iOS/Pod/Classes/Shader/DoricScrollerNode.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricScrollerNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
@interface DoricScrollView : UIScrollView
|
||||
@property(nonatomic, strong) UIView *contentView;
|
||||
@end
|
||||
|
||||
@interface DoricScrollerNode : DoricSuperNode<DoricScrollView *>
|
||||
@end
|
122
doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m
Normal file
122
doric-iOS/Pod/Classes/Shader/DoricScrollerNode.m
Normal file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricScrollerNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import "DoricScrollerNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricRefreshableNode.h"
|
||||
|
||||
@implementation DoricScrollView
|
||||
|
||||
- (void)setContentView:(UIView *)contentView {
|
||||
if (_contentView) {
|
||||
[_contentView removeFromSuperview];
|
||||
}
|
||||
_contentView = contentView;
|
||||
[self addSubview:contentView];
|
||||
}
|
||||
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.contentView) {
|
||||
return [self.contentView sizeThatFits:size];
|
||||
}
|
||||
return CGSizeZero;
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
[super layoutSelf:targetSize];
|
||||
[self setContentSize:self.contentView.frame.size];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@interface DoricScrollerNode ()
|
||||
@property(nonatomic, strong) DoricViewNode *childNode;
|
||||
@property(nonatomic, copy) NSString *childViewId;
|
||||
@end
|
||||
|
||||
@implementation DoricScrollerNode
|
||||
- (DoricScrollView *)build {
|
||||
return [DoricScrollView new];
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
if ([superNode isKindOfClass:[DoricRefreshableNode class]]) {
|
||||
self.view.bounces = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
NSDictionary *childModel = [self subModelOf:self.childViewId];
|
||||
if (!childModel) {
|
||||
return;
|
||||
}
|
||||
NSString *viewId = childModel[@"id"];
|
||||
NSString *type = childModel[@"type"];
|
||||
NSDictionary *childProps = childModel[@"props"];
|
||||
if (self.childNode) {
|
||||
if ([self.childNode.viewId isEqualToString:viewId]) {
|
||||
//skip
|
||||
} else {
|
||||
if (self.reusable && [type isEqualToString:self.childNode.type]) {
|
||||
[self.childNode also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it blend:childProps];
|
||||
}];
|
||||
} else {
|
||||
self.childNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.childNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
|
||||
it.viewId = viewId;
|
||||
[it initWithSuperNode:self];
|
||||
[it blend:childProps];
|
||||
self.view.contentView = it.view;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricScrollView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"content" isEqualToString:name]) {
|
||||
self.childViewId = prop;
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
[self.childNode blend:subModel[@"props"]];
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
if ([viewId isEqualToString:self.childViewId]) {
|
||||
return self.childNode;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
@end
|
26
doric-iOS/Pod/Classes/Shader/DoricSlideItemNode.h
Normal file
26
doric-iOS/Pod/Classes/Shader/DoricSlideItemNode.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSlideItemNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricStackNode.h"
|
||||
|
||||
@interface DoricSlideItemNode : DoricStackNode
|
||||
@end
|
51
doric-iOS/Pod/Classes/Shader/DoricSlideItemNode.m
Normal file
51
doric-iOS/Pod/Classes/Shader/DoricSlideItemNode.m
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSlideItemNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import "DoricSlideItemNode.h"
|
||||
|
||||
@interface DoricSlideItemView : DoricStackView
|
||||
@end
|
||||
|
||||
@implementation DoricSlideItemView
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DoricSlideItemNode
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
self.reusable = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
[super initWithSuperNode:superNode];
|
||||
self.reusable = YES;
|
||||
self.view.clipsToBounds = YES;
|
||||
}
|
||||
|
||||
- (DoricStackView *)build {
|
||||
return [DoricSlideItemView new];
|
||||
}
|
||||
@end
|
27
doric-iOS/Pod/Classes/Shader/DoricSliderNode.h
Normal file
27
doric-iOS/Pod/Classes/Shader/DoricSliderNode.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSliderNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "DoricSuperNode.h"
|
||||
|
||||
@interface DoricSliderNode : DoricSuperNode<UICollectionView *>
|
||||
@end
|
201
doric-iOS/Pod/Classes/Shader/DoricSliderNode.m
Normal file
201
doric-iOS/Pod/Classes/Shader/DoricSliderNode.m
Normal file
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricSliderNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/19.
|
||||
//
|
||||
#import <JavaScriptCore/JavaScriptCore.h>
|
||||
#import "DoricSliderNode.h"
|
||||
#import "Doric.h"
|
||||
#import "DoricSlideItemNode.h"
|
||||
|
||||
@interface DoricSliderViewCell : UICollectionViewCell
|
||||
@property(nonatomic, strong) DoricSlideItemNode *doricSlideItemNode;
|
||||
@end
|
||||
|
||||
@implementation DoricSliderViewCell
|
||||
@end
|
||||
|
||||
@interface DoricSliderNode () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
|
||||
@property(nonatomic, assign) NSUInteger itemCount;
|
||||
@property(nonatomic, assign) NSUInteger batchCount;
|
||||
@end
|
||||
|
||||
@interface DoricSliderView : UICollectionView
|
||||
@end
|
||||
|
||||
@implementation DoricSliderView
|
||||
- (CGSize)sizeThatFits:(CGSize)size {
|
||||
if (self.subviews.count > 0) {
|
||||
CGFloat width = size.width;
|
||||
CGFloat height = size.height;
|
||||
for (UIView *child in self.subviews) {
|
||||
CGSize childSize = [child measureSize:size];
|
||||
width = MAX(childSize.width, width);
|
||||
height = MAX(childSize.height, height);
|
||||
}
|
||||
return CGSizeMake(width, height);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
- (void)layoutSelf:(CGSize)targetSize {
|
||||
[super layoutSelf:targetSize];
|
||||
[self reloadData];
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation DoricSliderNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_itemViewIds = [NSMutableDictionary new];
|
||||
_batchCount = 15;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UICollectionView *)build {
|
||||
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
|
||||
[flowLayout setScrollDirection:UICollectionViewScrollDirectionHorizontal];
|
||||
|
||||
return [[[DoricSliderView alloc] initWithFrame:CGRectZero
|
||||
collectionViewLayout:flowLayout]
|
||||
also:^(UICollectionView *it) {
|
||||
it.backgroundColor = [UIColor whiteColor];
|
||||
it.pagingEnabled = YES;
|
||||
it.delegate = self;
|
||||
it.dataSource = self;
|
||||
[it registerClass:[DoricSliderViewCell class] forCellWithReuseIdentifier:@"doricCell"];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"itemCount" isEqualToString:name]) {
|
||||
self.itemCount = [prop unsignedIntegerValue];
|
||||
[self.view reloadData];
|
||||
} else if ([@"renderPage" isEqualToString:name]) {
|
||||
[self.itemViewIds removeAllObjects];
|
||||
[self clearSubModel];
|
||||
[self.view reloadData];
|
||||
} else if ([@"batchCount" isEqualToString:name]) {
|
||||
self.batchCount = [prop unsignedIntegerValue];
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||
return self.itemCount;
|
||||
}
|
||||
|
||||
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return CGSizeMake(self.view.width, self.view.height);
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumInteritemSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section {
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
NSUInteger position = (NSUInteger) indexPath.row;
|
||||
NSDictionary *model = [self itemModelAt:position];
|
||||
NSDictionary *props = model[@"props"];
|
||||
DoricSliderViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"doricCell" forIndexPath:indexPath];
|
||||
if (!cell.doricSlideItemNode) {
|
||||
DoricSlideItemNode *slideItemNode = [[DoricSlideItemNode alloc] initWithContext:self.doricContext];
|
||||
[slideItemNode initWithSuperNode:self];
|
||||
cell.doricSlideItemNode = slideItemNode;
|
||||
[cell.contentView addSubview:slideItemNode.view];
|
||||
}
|
||||
DoricSlideItemNode *node = cell.doricSlideItemNode;
|
||||
node.viewId = model[@"id"];
|
||||
[node blend:props];
|
||||
CGSize size = [node.view measureSize:CGSizeMake(collectionView.width, collectionView.height)];
|
||||
[node.view layoutSelf:size];
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (NSDictionary *)itemModelAt:(NSUInteger)position {
|
||||
NSString *viewId = self.itemViewIds[@(position)];
|
||||
if (viewId && viewId.length > 0) {
|
||||
return [self subModelOf:viewId];
|
||||
} else {
|
||||
DoricAsyncResult *result = [self callJSResponse:@"renderBunchedItems", @(position), @(self.batchCount), nil];
|
||||
JSValue *models = [result waitUntilResult];
|
||||
NSArray *array = [models toArray];
|
||||
[array enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
|
||||
NSString *thisViewId = obj[@"id"];
|
||||
[self setSubModel:obj in:thisViewId];
|
||||
NSUInteger pos = position + idx;
|
||||
self.itemViewIds[@(pos)] = thisViewId;
|
||||
}];
|
||||
return array[0];
|
||||
}
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
__block DoricViewNode *ret = nil;
|
||||
[self.doricContext.driver ensureSyncInMainQueue:^{
|
||||
for (UICollectionViewCell *collectionViewCell in self.view.visibleCells) {
|
||||
if ([collectionViewCell isKindOfClass:[DoricSliderViewCell class]]) {
|
||||
DoricSlideItemNode *node = ((DoricSliderViewCell *) collectionViewCell).doricSlideItemNode;
|
||||
if ([viewId isEqualToString:node.viewId]) {
|
||||
ret = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}];
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
NSString *viewId = subModel[@"id"];
|
||||
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
|
||||
if (viewNode) {
|
||||
[viewNode blend:subModel[@"props"]];
|
||||
} else {
|
||||
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
|
||||
[self recursiveMixin:subModel to:model];
|
||||
[self setSubModel:model in:viewId];
|
||||
}
|
||||
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
|
||||
if ([viewId isEqualToString:obj]) {
|
||||
*stop = YES;
|
||||
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
|
||||
[UIView performWithoutAnimation:^{
|
||||
[self.view reloadItemsAtIndexPaths:@[indexPath]];
|
||||
}];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
|
||||
NSUInteger pageIndex = (NSUInteger) (scrollView.contentOffset.x / scrollView.width);
|
||||
scrollView.contentOffset = CGPointMake(pageIndex * scrollView.width, scrollView.contentOffset.y);
|
||||
}
|
||||
@end
|
26
doric-iOS/Pod/Classes/Shader/DoricStackNode.h
Normal file
26
doric-iOS/Pod/Classes/Shader/DoricStackNode.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricStackNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricGroupNode.h"
|
||||
|
||||
@interface DoricStackNode : DoricGroupNode<DoricStackView *>
|
||||
@end
|
34
doric-iOS/Pod/Classes/Shader/DoricStackNode.m
Normal file
34
doric-iOS/Pod/Classes/Shader/DoricStackNode.m
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricStackNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricStackNode.h"
|
||||
|
||||
@implementation DoricStackNode
|
||||
|
||||
- (DoricStackView *)build {
|
||||
return [DoricStackView new];
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricStackView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
@end
|
41
doric-iOS/Pod/Classes/Shader/DoricSuperNode.h
Normal file
41
doric-iOS/Pod/Classes/Shader/DoricSuperNode.h
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "DoricViewNode.h"
|
||||
|
||||
@interface DoricSuperNode<V:UIView *> : DoricViewNode<V>
|
||||
@property(nonatomic, assign) BOOL reusable;
|
||||
|
||||
- (DoricLayoutConfig *)generateDefaultLayoutParams;
|
||||
|
||||
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig;
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel;
|
||||
|
||||
- (NSDictionary *)subModelOf:(NSString *)viewId;
|
||||
|
||||
- (void)setSubModel:(NSDictionary *)model in:(NSString *)viewId;
|
||||
|
||||
- (void)clearSubModel;
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId;
|
||||
|
||||
- (void)recursiveMixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel;
|
||||
@end
|
160
doric-iOS/Pod/Classes/Shader/DoricSuperNode.m
Normal file
160
doric-iOS/Pod/Classes/Shader/DoricSuperNode.m
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/11/15.
|
||||
//
|
||||
|
||||
#import "DoricSuperNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
|
||||
@interface DoricSuperNode ()
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSString *, NSMutableDictionary *> *subNodes;
|
||||
@end
|
||||
|
||||
@implementation DoricSuperNode
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_subNodes = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([@"subviews" isEqualToString:name]) {
|
||||
NSArray *subviews = prop;
|
||||
for (NSMutableDictionary *subModel in subviews) {
|
||||
[self mixinSubNode:subModel];
|
||||
[self blendSubNode:subModel];
|
||||
}
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mixinSubNode:(NSMutableDictionary *)dictionary {
|
||||
NSString *viewId = dictionary[@"id"];
|
||||
NSMutableDictionary *oldModel = self.subNodes[viewId];
|
||||
if (oldModel) {
|
||||
[self mixin:dictionary to:oldModel];
|
||||
} else {
|
||||
self.subNodes[viewId] = dictionary;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel {
|
||||
NSDictionary *srcProp = srcModel[@"props"];
|
||||
NSMutableDictionary *targetProp = targetModel[@"props"];
|
||||
[srcProp enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||
if (![@"subviews" isEqualToString:key]) {
|
||||
targetProp[key] = obj;
|
||||
}
|
||||
}];
|
||||
targetModel[@"props"] = targetProp;
|
||||
}
|
||||
|
||||
- (void)recursiveMixin:(NSDictionary *)srcModel to:(NSMutableDictionary *)targetModel {
|
||||
NSDictionary *srcProp = srcModel[@"props"];
|
||||
NSMutableDictionary *targetProp = targetModel[@"props"];
|
||||
NSMutableArray *targetOri = targetProp[@"subviews"];
|
||||
|
||||
[srcProp enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
|
||||
if ([@"subviews" isEqualToString:key]) {
|
||||
NSArray *subviews = obj;
|
||||
if (subviews) {
|
||||
for (NSDictionary *subview in subviews) {
|
||||
NSString *viewId = subview[@"id"];
|
||||
[targetOri enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
|
||||
if ([viewId isEqualToString:obj[@"id"]]) {
|
||||
NSMutableDictionary *mutableDictionary = [obj mutableCopy];
|
||||
[self recursiveMixin:subview to:mutableDictionary];
|
||||
targetOri[idx] = [mutableDictionary copy];
|
||||
*stop = YES;
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
targetProp[key] = obj;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(DoricViewNode *)subNode layoutConfig:(NSDictionary *)layoutConfig {
|
||||
DoricLayoutConfig *params = subNode.layoutConfig;
|
||||
|
||||
[layoutConfig[@"widthSpec"] also:^(NSNumber *it) {
|
||||
if (it) {
|
||||
params.widthSpec = (DoricLayoutSpec) [it integerValue];
|
||||
}
|
||||
}];
|
||||
|
||||
[layoutConfig[@"heightSpec"] also:^(NSNumber *it) {
|
||||
if (it) {
|
||||
params.heightSpec = (DoricLayoutSpec) [it integerValue];
|
||||
}
|
||||
}];
|
||||
|
||||
NSDictionary *margin = layoutConfig[@"margin"];
|
||||
if (margin) {
|
||||
params.margin = DoricMarginMake(
|
||||
[(NSNumber *) margin[@"left"] floatValue],
|
||||
[(NSNumber *) margin[@"top"] floatValue],
|
||||
[(NSNumber *) margin[@"right"] floatValue],
|
||||
[(NSNumber *) margin[@"bottom"] floatValue]);
|
||||
}
|
||||
|
||||
NSNumber *alignment = layoutConfig[@"alignment"];
|
||||
if (alignment) {
|
||||
params.alignment = (DoricGravity) [alignment integerValue];
|
||||
}
|
||||
NSNumber *weight = layoutConfig[@"weight"];
|
||||
if (weight) {
|
||||
params.weight = (DoricGravity) [weight integerValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendSubNode:(NSDictionary *)subModel {
|
||||
NSAssert(NO, @"Should override class:%@ ,method:%@.", NSStringFromClass([self class]),
|
||||
NSStringFromSelector(_cmd));
|
||||
}
|
||||
|
||||
- (DoricLayoutConfig *)generateDefaultLayoutParams {
|
||||
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init];
|
||||
return params;
|
||||
}
|
||||
|
||||
|
||||
- (NSDictionary *)subModelOf:(NSString *)viewId {
|
||||
return self.subNodes[viewId];
|
||||
}
|
||||
|
||||
- (void)setSubModel:(NSDictionary *)model in:(NSString *)viewId {
|
||||
self.subNodes[viewId] = [model mutableCopy];
|
||||
}
|
||||
|
||||
- (void)clearSubModel {
|
||||
[self.subNodes removeAllObjects];
|
||||
}
|
||||
|
||||
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
|
||||
NSAssert(NO, @"Should override class:%@ ,method:%@.", NSStringFromClass([self class]),
|
||||
NSStringFromSelector(_cmd));
|
||||
return nil;
|
||||
}
|
||||
- (void)requestLayout {
|
||||
[self.view setNeedsLayout];
|
||||
}
|
||||
@end
|
31
doric-iOS/Pod/Classes/Shader/DoricTextNode.h
Normal file
31
doric-iOS/Pod/Classes/Shader/DoricTextNode.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricTextNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/31.
|
||||
//
|
||||
|
||||
#import "DoricViewNode.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricTextNode : DoricViewNode<UILabel *>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
60
doric-iOS/Pod/Classes/Shader/DoricTextNode.m
Normal file
60
doric-iOS/Pod/Classes/Shader/DoricTextNode.m
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricTextNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/31.
|
||||
//
|
||||
|
||||
#import "DoricTextNode.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricGroupNode.h"
|
||||
#import "Doric.h"
|
||||
|
||||
@implementation DoricTextNode
|
||||
- (UILabel *)build {
|
||||
return [[[UILabel alloc] init] also:^(UILabel *it) {
|
||||
it.textAlignment = NSTextAlignmentCenter;
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)blendView:(UILabel *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([name isEqualToString:@"text"]) {
|
||||
view.text = prop;
|
||||
} else if ([name isEqualToString:@"textSize"]) {
|
||||
view.font = [UIFont systemFontOfSize:[(NSNumber *) prop floatValue]];
|
||||
} else if ([name isEqualToString:@"textColor"]) {
|
||||
view.textColor = DoricColor(prop);
|
||||
} else if ([name isEqualToString:@"textAlignment"]) {
|
||||
DoricGravity gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||
NSTextAlignment alignment = NSTextAlignmentCenter;
|
||||
if ((gravity & LEFT) == LEFT) {
|
||||
alignment = NSTextAlignmentLeft;
|
||||
} else if ((gravity & RIGHT) == RIGHT) {
|
||||
alignment = NSTextAlignmentRight;
|
||||
}
|
||||
view.textAlignment = alignment;
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
[super blend:props];
|
||||
[self.view.superview setNeedsLayout];
|
||||
}
|
||||
@end
|
26
doric-iOS/Pod/Classes/Shader/DoricVLayoutNode.h
Normal file
26
doric-iOS/Pod/Classes/Shader/DoricVLayoutNode.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricVLayoutNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricGroupNode.h"
|
||||
|
||||
@interface DoricVLayoutNode : DoricGroupNode<DoricVLayoutView *>
|
||||
@end
|
41
doric-iOS/Pod/Classes/Shader/DoricVLayoutNode.m
Normal file
41
doric-iOS/Pod/Classes/Shader/DoricVLayoutNode.m
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricVLayoutNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricVLayoutNode.h"
|
||||
|
||||
@implementation DoricVLayoutNode
|
||||
|
||||
- (DoricVLayoutView *)build {
|
||||
return [DoricVLayoutView new];
|
||||
}
|
||||
|
||||
- (void)blendView:(DoricVLayoutView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([name isEqualToString:@"gravity"]) {
|
||||
view.gravity = (DoricGravity) [(NSNumber *) prop integerValue];
|
||||
} else if ([name isEqualToString:@"space"]) {
|
||||
view.space = [(NSNumber *) prop floatValue];
|
||||
} else {
|
||||
[super blendView:view forPropName:name propValue:prop];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
56
doric-iOS/Pod/Classes/Shader/DoricViewNode.h
Normal file
56
doric-iOS/Pod/Classes/Shader/DoricViewNode.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricViewNode.h
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricContextHolder.h"
|
||||
#import "DoricLayouts.h"
|
||||
#import "UIView+Doric.h"
|
||||
|
||||
@class DoricSuperNode;
|
||||
|
||||
@interface DoricViewNode <V:UIView *> : DoricContextHolder
|
||||
|
||||
@property(nonatomic, strong) V view;
|
||||
@property(nonatomic, weak) DoricSuperNode *superNode;
|
||||
@property(nonatomic) NSInteger index;
|
||||
|
||||
@property(nonatomic, copy) NSString *viewId;
|
||||
|
||||
@property(nonatomic, copy) NSString *type;
|
||||
|
||||
@property(nonatomic, readonly) DoricLayoutConfig *layoutConfig;
|
||||
|
||||
@property(nonatomic, readonly) NSArray<NSString *> *idList;
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode;
|
||||
|
||||
- (V)build;
|
||||
|
||||
- (void)blend:(NSDictionary *)props;
|
||||
|
||||
- (void)blendView:(V)view forPropName:(NSString *)name propValue:(id)prop;
|
||||
|
||||
- (DoricAsyncResult *)callJSResponse:(NSString *)funcId, ...;
|
||||
|
||||
+ (__kindof DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type;
|
||||
|
||||
- (void)requestLayout;
|
||||
@end
|
627
doric-iOS/Pod/Classes/Shader/DoricViewNode.m
Normal file
627
doric-iOS/Pod/Classes/Shader/DoricViewNode.m
Normal file
@@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// DoricViewNode.m
|
||||
// Doric
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/30.
|
||||
//
|
||||
|
||||
#import "DoricViewNode.h"
|
||||
#import "DoricUtil.h"
|
||||
#import "DoricGroupNode.h"
|
||||
#import "DoricRootNode.h"
|
||||
#import "DoricConstant.h"
|
||||
#import "DoricSuperNode.h"
|
||||
#import "DoricExtensions.h"
|
||||
#import "DoricPromise.h"
|
||||
|
||||
void DoricAddEllipticArcPath(CGMutablePathRef path,
|
||||
CGPoint origin,
|
||||
CGFloat radius,
|
||||
CGFloat startAngle,
|
||||
CGFloat endAngle) {
|
||||
CGAffineTransform t = CGAffineTransformMakeTranslation(origin.x, origin.y);
|
||||
CGPathAddArc(path, &t, 0, 0, radius, startAngle, endAngle, NO);
|
||||
}
|
||||
|
||||
|
||||
CGPathRef DoricCreateRoundedRectPath(CGRect bounds,
|
||||
CGFloat leftTop,
|
||||
CGFloat rightTop,
|
||||
CGFloat rightBottom,
|
||||
CGFloat leftBottom) {
|
||||
const CGFloat minX = CGRectGetMinX(bounds);
|
||||
const CGFloat minY = CGRectGetMinY(bounds);
|
||||
const CGFloat maxX = CGRectGetMaxX(bounds);
|
||||
const CGFloat maxY = CGRectGetMaxY(bounds);
|
||||
|
||||
CGMutablePathRef path = CGPathCreateMutable();
|
||||
DoricAddEllipticArcPath(path, (CGPoint) {
|
||||
minX + leftTop, minY + leftTop
|
||||
}, leftTop, M_PI, 3 * M_PI_2);
|
||||
DoricAddEllipticArcPath(path, (CGPoint) {
|
||||
maxX - rightTop, minY + rightTop
|
||||
}, rightTop, 3 * M_PI_2, 0);
|
||||
DoricAddEllipticArcPath(path, (CGPoint) {
|
||||
maxX - rightBottom, maxY - rightBottom
|
||||
}, rightBottom, 0, M_PI_2);
|
||||
DoricAddEllipticArcPath(path, (CGPoint) {
|
||||
minX + leftBottom, maxY - leftBottom
|
||||
}, leftBottom, M_PI_2, M_PI);
|
||||
CGPathCloseSubpath(path);
|
||||
return path;
|
||||
}
|
||||
|
||||
@interface AnimationCallback : NSObject <CAAnimationDelegate>
|
||||
@property(nonatomic, strong) NSMutableDictionary *dictionary;
|
||||
@property(nonatomic, strong) void (^startBlock)(AnimationCallback *callback);
|
||||
|
||||
@property(nonatomic, strong) void (^endBlock)(AnimationCallback *callback);
|
||||
@end
|
||||
|
||||
@implementation AnimationCallback
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
_dictionary = [NSMutableDictionary new];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)animationDidStart:(CAAnimation *)anim {
|
||||
if (self.startBlock) {
|
||||
self.startBlock(self);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
|
||||
if (self.endBlock) {
|
||||
self.endBlock(self);
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
@interface DoricViewNode ()
|
||||
@property(nonatomic, strong) NSMutableDictionary *callbackIds;
|
||||
@property(nonatomic, copy) NSNumber *translationX;
|
||||
@property(nonatomic, copy) NSNumber *translationY;
|
||||
@property(nonatomic, copy) NSNumber *scaleX;
|
||||
@property(nonatomic, copy) NSNumber *scaleY;
|
||||
@property(nonatomic, copy) NSNumber *rotation;
|
||||
@property(nonatomic, copy) NSNumber *pivotX;
|
||||
@property(nonatomic, copy) NSNumber *pivotY;
|
||||
@end
|
||||
|
||||
@implementation DoricViewNode
|
||||
|
||||
- (instancetype)initWithContext:(DoricContext *)doricContext {
|
||||
if (self = [super initWithContext:doricContext]) {
|
||||
_callbackIds = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
|
||||
if ([self isKindOfClass:[DoricSuperNode class]]) {
|
||||
((DoricSuperNode *) self).reusable = superNode.reusable;
|
||||
}
|
||||
self.superNode = superNode;
|
||||
self.view = [[self build] also:^(UIView *it) {
|
||||
it.layoutConfig = [superNode generateDefaultLayoutParams];
|
||||
}];
|
||||
}
|
||||
|
||||
- (DoricLayoutConfig *)layoutConfig {
|
||||
return self.view.layoutConfig;
|
||||
}
|
||||
|
||||
- (UIView *)build {
|
||||
return [[UIView alloc] init];
|
||||
}
|
||||
|
||||
- (void)blend:(NSDictionary *)props {
|
||||
self.view.layoutConfig = self.layoutConfig;
|
||||
for (NSString *key in props) {
|
||||
id value = props[key];
|
||||
[self blendView:self.view forPropName:key propValue:value];
|
||||
}
|
||||
[self transformProperties];
|
||||
}
|
||||
|
||||
- (void)transformProperties {
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
if (self.translationX || self.translationY) {
|
||||
transform = CGAffineTransformTranslate(transform, [self.translationX floatValue] ?: 0, [self.translationY floatValue] ?: 0);
|
||||
}
|
||||
if (self.scaleX || self.scaleY) {
|
||||
transform = CGAffineTransformScale(transform, [self.scaleX floatValue] ?: 1, [self.scaleY floatValue] ?: 1);
|
||||
}
|
||||
if (self.rotation) {
|
||||
transform = CGAffineTransformRotate(transform, (self.rotation.floatValue ?: 0) * M_PI);
|
||||
}
|
||||
if (!CGAffineTransformEqualToTransform(transform, self.view.transform)) {
|
||||
self.view.transform = transform;
|
||||
}
|
||||
if (self.pivotX || self.pivotY) {
|
||||
self.view.layer.anchorPoint = CGPointMake(self.pivotX.floatValue
|
||||
?: 0.5f, self.pivotY.floatValue ?: 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
|
||||
if ([name isEqualToString:@"width"]) {
|
||||
NSNumber *width = (NSNumber *) prop;
|
||||
if ([width floatValue] >= 0) {
|
||||
view.width = [width floatValue];
|
||||
}
|
||||
} else if ([name isEqualToString:@"height"]) {
|
||||
NSNumber *height = (NSNumber *) prop;
|
||||
if ([height floatValue] >= 0) {
|
||||
view.height = [height floatValue];
|
||||
}
|
||||
} else if ([name isEqualToString:@"x"]) {
|
||||
view.x = [(NSNumber *) prop floatValue];
|
||||
} else if ([name isEqualToString:@"y"]) {
|
||||
view.y = [(NSNumber *) prop floatValue];
|
||||
} else if ([name isEqualToString:@"backgroundColor"]) {
|
||||
view.backgroundColor = DoricColor(prop);
|
||||
} else if ([name isEqualToString:@"alpha"]) {
|
||||
view.alpha = [prop floatValue];
|
||||
} else if ([name isEqualToString:@"layoutConfig"]) {
|
||||
if (self.superNode && [prop isKindOfClass:[NSDictionary class]]) {
|
||||
[self.superNode blendSubNode:self layoutConfig:prop];
|
||||
} else {
|
||||
[self blendLayoutConfig:prop];
|
||||
}
|
||||
} else if ([name isEqualToString:@"onClick"]) {
|
||||
self.callbackIds[@"onClick"] = prop;
|
||||
view.userInteractionEnabled = YES;
|
||||
UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(onClick:)];
|
||||
[view addGestureRecognizer:tapGestureRecognizer];
|
||||
} else if ([name isEqualToString:@"border"]) {
|
||||
NSDictionary *dic = prop;
|
||||
CGFloat width = [(NSNumber *) dic[@"width"] floatValue];
|
||||
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
|
||||
view.layer.borderWidth = width;
|
||||
view.layer.borderColor = color.CGColor;
|
||||
} else if ([name isEqualToString:@"corners"]) {
|
||||
if ([prop isKindOfClass:NSNumber.class]) {
|
||||
view.layer.cornerRadius = [(NSNumber *) prop floatValue];
|
||||
} else if ([prop isKindOfClass:NSDictionary.class]) {
|
||||
NSDictionary *dic = prop;
|
||||
CGFloat leftTop = [(NSNumber *) dic[@"leftTop"] floatValue];
|
||||
CGFloat rightTop = [(NSNumber *) dic[@"rightTop"] floatValue];
|
||||
CGFloat rightBottom = [(NSNumber *) dic[@"rightBottom"] floatValue];
|
||||
CGFloat leftBottom = [(NSNumber *) dic[@"leftBottom"] floatValue];
|
||||
if (ABS(leftTop - rightTop) > CGFLOAT_MIN
|
||||
|| ABS(leftTop - rightBottom) > CGFLOAT_MIN
|
||||
|| ABS(leftTop - leftBottom) > CGFLOAT_MIN) {
|
||||
view.layer.cornerRadius = 0;
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
|
||||
CGPathRef path = DoricCreateRoundedRectPath(self.view.bounds, leftTop, rightTop, rightBottom, leftBottom);
|
||||
shapeLayer.path = path;
|
||||
CGPathRelease(path);
|
||||
view.layer.mask = shapeLayer;
|
||||
});
|
||||
} else {
|
||||
view.layer.cornerRadius = leftTop;
|
||||
view.layer.mask = nil;
|
||||
}
|
||||
}
|
||||
} else if ([name isEqualToString:@"shadow"]) {
|
||||
NSDictionary *dic = prop;
|
||||
CGFloat opacity = [(NSNumber *) dic[@"opacity"] floatValue];
|
||||
if (opacity > CGFLOAT_MIN) {
|
||||
view.clipsToBounds = NO;
|
||||
UIColor *color = DoricColor((NSNumber *) dic[@"color"]);
|
||||
view.layer.shadowColor = color.CGColor;
|
||||
view.layer.shadowRadius = [(NSNumber *) dic[@"radius"] floatValue];
|
||||
view.layer.shadowOffset = CGSizeMake([(NSNumber *) dic[@"offsetX"] floatValue], [(NSNumber *) dic[@"offsetY"] floatValue]);
|
||||
view.layer.shadowOpacity = (float) opacity;
|
||||
} else {
|
||||
view.clipsToBounds = YES;
|
||||
}
|
||||
|
||||
} else if ([name isEqualToString:@"translationX"]) {
|
||||
self.translationX = prop;
|
||||
} else if ([name isEqualToString:@"translationY"]) {
|
||||
self.translationY = prop;
|
||||
} else if ([name isEqualToString:@"scaleX"]) {
|
||||
self.scaleX = prop;
|
||||
} else if ([name isEqualToString:@"scaleY"]) {
|
||||
self.scaleY = prop;
|
||||
} else if ([name isEqualToString:@"pivotX"]) {
|
||||
self.pivotX = prop;
|
||||
} else if ([name isEqualToString:@"pivotY"]) {
|
||||
self.pivotY = prop;
|
||||
} else if ([name isEqualToString:@"rotation"]) {
|
||||
self.rotation = prop;
|
||||
} else {
|
||||
DoricLog(@"Blend View error for View Type :%@, prop is %@", self.class, name);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onClick:(UIView *)view {
|
||||
[self callJSResponse:self.callbackIds[@"onClick"], nil];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)idList {
|
||||
NSMutableArray *ret = [[NSMutableArray alloc] init];
|
||||
DoricViewNode *node = self;
|
||||
do {
|
||||
[ret addObject:node.viewId];
|
||||
node = node.superNode;
|
||||
} while (node);
|
||||
|
||||
return [[ret reverseObjectEnumerator] allObjects];
|
||||
}
|
||||
|
||||
- (DoricAsyncResult *)callJSResponse:(NSString *)funcId, ... {
|
||||
NSMutableArray *array = [[NSMutableArray alloc] init];
|
||||
[array addObject:self.idList];
|
||||
[array addObject:funcId];
|
||||
va_list args;
|
||||
va_start(args, funcId);
|
||||
id arg;
|
||||
while ((arg = va_arg(args, id)) != nil) {
|
||||
[array addObject:arg];
|
||||
}
|
||||
DoricAsyncResult *ret = [self.doricContext callEntity:DORIC_ENTITY_RESPONSE withArgumentsArray:array];
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (__kindof DoricViewNode *)create:(DoricContext *)context withType:(NSString *)type {
|
||||
DoricRegistry *registry = context.driver.registry;
|
||||
Class clz = [registry acquireViewNode:type];
|
||||
DoricViewNode *viewNode = [(DoricViewNode *) [clz alloc] initWithContext:context];
|
||||
viewNode.type = type;
|
||||
return viewNode;
|
||||
}
|
||||
|
||||
- (void)requestLayout {
|
||||
[self.superNode requestLayout];
|
||||
}
|
||||
|
||||
- (NSNumber *)getWidth {
|
||||
return @(self.view.width);
|
||||
}
|
||||
|
||||
- (NSNumber *)getHeight {
|
||||
return @(self.view.height);
|
||||
}
|
||||
|
||||
- (void)blendLayoutConfig:(NSDictionary *)params {
|
||||
[params[@"widthSpec"] also:^(NSNumber *it) {
|
||||
if (it) {
|
||||
self.layoutConfig.widthSpec = (DoricLayoutSpec) [it integerValue];
|
||||
}
|
||||
}];
|
||||
|
||||
[params[@"heightSpec"] also:^(NSNumber *it) {
|
||||
if (it) {
|
||||
self.layoutConfig.heightSpec = (DoricLayoutSpec) [it integerValue];
|
||||
}
|
||||
}];
|
||||
|
||||
NSDictionary *margin = params[@"margin"];
|
||||
if (margin) {
|
||||
self.layoutConfig.margin = DoricMarginMake(
|
||||
[(NSNumber *) margin[@"left"] floatValue],
|
||||
[(NSNumber *) margin[@"top"] floatValue],
|
||||
[(NSNumber *) margin[@"right"] floatValue],
|
||||
[(NSNumber *) margin[@"bottom"] floatValue]);
|
||||
}
|
||||
|
||||
NSNumber *alignment = params[@"alignment"];
|
||||
if (alignment) {
|
||||
self.layoutConfig.alignment = (DoricGravity) [alignment integerValue];
|
||||
}
|
||||
NSNumber *weight = params[@"weight"];
|
||||
if (weight) {
|
||||
self.layoutConfig.weight = (DoricGravity) [weight integerValue];
|
||||
}
|
||||
}
|
||||
|
||||
- (NSDictionary *)transformation {
|
||||
NSMutableDictionary *dictionary = [NSMutableDictionary new];
|
||||
if (self.translationX) {
|
||||
dictionary[@"translationX"] = self.translationX;
|
||||
}
|
||||
if (self.translationY) {
|
||||
dictionary[@"translationY"] = self.translationY;
|
||||
}
|
||||
if (self.scaleX) {
|
||||
dictionary[@"scaleX"] = self.scaleX;
|
||||
}
|
||||
if (self.scaleY) {
|
||||
dictionary[@"scaleY"] = self.scaleY;
|
||||
}
|
||||
if (self.rotation) {
|
||||
dictionary[@"rotation"] = self.rotation;
|
||||
}
|
||||
return dictionary;
|
||||
}
|
||||
|
||||
- (void)doAnimation:(id)params withPromise:(DoricPromise *)promise {
|
||||
CAAnimation *animation = [self parseAnimation:params];
|
||||
AnimationCallback *originDelegate = animation.delegate;
|
||||
AnimationCallback *animationCallback = [[AnimationCallback new] also:^(AnimationCallback *it) {
|
||||
it.startBlock = ^(AnimationCallback *callback) {
|
||||
if (originDelegate) {
|
||||
originDelegate.startBlock(callback);
|
||||
}
|
||||
[self transformProperties];
|
||||
};
|
||||
it.endBlock = ^(AnimationCallback *callback) {
|
||||
if (originDelegate) {
|
||||
originDelegate.endBlock(callback);
|
||||
}
|
||||
[self transformProperties];
|
||||
[promise resolve:self.transformation];
|
||||
};
|
||||
}];
|
||||
animation.delegate = animationCallback;
|
||||
if (params[@"delay"]) {
|
||||
animation.beginTime = CACurrentMediaTime() + [params[@"delay"] floatValue] / 1000;
|
||||
}
|
||||
[self.view.layer addAnimation:animation forKey:nil];
|
||||
}
|
||||
|
||||
- (CFTimeInterval)computeDurationOfAnimations:(NSArray<CAAnimation *> *)animations {
|
||||
__block CFTimeInterval interval = 0;
|
||||
[animations forEach:^(CAAnimation *obj) {
|
||||
interval = MAX(interval, obj.beginTime + obj.duration * (1 + obj.repeatCount));
|
||||
}];
|
||||
return interval;
|
||||
}
|
||||
|
||||
- (CAAnimation *)parseAnimation:(id)params {
|
||||
if (params[@"animations"]) {
|
||||
NSArray *anims = params[@"animations"];
|
||||
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
|
||||
NSMutableArray *animations = [NSMutableArray new];
|
||||
[anims forEach:^(id obj) {
|
||||
[animations addObject:[self parseAnimation:obj]];
|
||||
}];
|
||||
animationGroup.duration = [self computeDurationOfAnimations:animations];
|
||||
animationGroup.animations = animations;
|
||||
animationGroup.delegate = [[AnimationCallback new] also:^(AnimationCallback *it) {
|
||||
it.startBlock = ^(AnimationCallback *callback) {
|
||||
[[animations map:^id(CABasicAnimation *obj) {
|
||||
return obj.delegate;
|
||||
}] forEach:^(AnimationCallback *obj) {
|
||||
if (obj.startBlock) {
|
||||
obj.startBlock(obj);
|
||||
}
|
||||
}];
|
||||
};
|
||||
it.endBlock = ^(AnimationCallback *callback) {
|
||||
[[animations map:^id(CABasicAnimation *obj) {
|
||||
return obj.delegate;
|
||||
}] forEach:^(AnimationCallback *obj) {
|
||||
if (obj.endBlock) {
|
||||
obj.endBlock(obj);
|
||||
}
|
||||
}];
|
||||
};
|
||||
}];
|
||||
if (params[@"delay"]) {
|
||||
animationGroup.beginTime = [params[@"delay"] floatValue] / 1000;
|
||||
}
|
||||
return animationGroup;
|
||||
} else if ([params isKindOfClass:[NSDictionary class]]) {
|
||||
NSArray<NSDictionary *> *changeables = params[@"changeables"];
|
||||
NSString *type = params[@"type"];
|
||||
if ([@"TranslationAnimation" isEqualToString:type]) {
|
||||
__block CGPoint from = self.view.layer.position;
|
||||
__block CGPoint to = self.view.layer.position;
|
||||
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
|
||||
[changeables forEach:^(NSDictionary *obj) {
|
||||
NSString *key = obj[@"key"];
|
||||
if ([@"translationX" isEqualToString:key]) {
|
||||
from.x += [obj[@"fromValue"] floatValue] - self.translationX.floatValue;
|
||||
to.x += [obj[@"toValue"] floatValue] - self.translationX.floatValue;
|
||||
[self setFillMode:animation
|
||||
key:key
|
||||
startValue:obj[@"fromValue"]
|
||||
endValue:obj[@"toValue"]
|
||||
fillMode:params[@"fillMode"]];
|
||||
} else if ([@"translationY" isEqualToString:key]) {
|
||||
from.y += [obj[@"fromValue"] floatValue] - self.translationY.floatValue;
|
||||
to.y += [obj[@"toValue"] floatValue] - self.translationY.floatValue;
|
||||
[self setFillMode:animation
|
||||
key:key
|
||||
startValue:obj[@"fromValue"]
|
||||
endValue:obj[@"toValue"]
|
||||
fillMode:params[@"fillMode"]];
|
||||
}
|
||||
|
||||
}];
|
||||
animation.fromValue = [NSValue valueWithCGPoint:from];
|
||||
animation.toValue = [NSValue valueWithCGPoint:to];
|
||||
if (params[@"timingFunction"]) {
|
||||
animation.timingFunction = [self translateToTimingFunction:params[@"timingFunction"]];
|
||||
}
|
||||
[self setAnimation:animation params:params];
|
||||
return animation;
|
||||
} else {
|
||||
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
|
||||
NSMutableArray <CABasicAnimation *> *animations = [NSMutableArray new];
|
||||
|
||||
[changeables forEach:^(NSDictionary *obj) {
|
||||
CABasicAnimation *animation = [self parseChangeable:obj fillMode:params[@"fillMode"]];
|
||||
if (params[@"timingFunction"]) {
|
||||
animation.timingFunction = [self translateToTimingFunction:params[@"timingFunction"]];
|
||||
}
|
||||
[animations addObject:animation];
|
||||
}];
|
||||
animationGroup.animations = animations;
|
||||
animationGroup.delegate = [[AnimationCallback new] also:^(AnimationCallback *it) {
|
||||
it.startBlock = ^(AnimationCallback *callback) {
|
||||
[[animations map:^id(CABasicAnimation *obj) {
|
||||
return obj.delegate;
|
||||
}] forEach:^(AnimationCallback *obj) {
|
||||
if (obj.startBlock) {
|
||||
obj.startBlock(obj);
|
||||
}
|
||||
}];
|
||||
};
|
||||
it.endBlock = ^(AnimationCallback *callback) {
|
||||
[[animations map:^id(CABasicAnimation *obj) {
|
||||
return obj.delegate;
|
||||
}] forEach:^(AnimationCallback *obj) {
|
||||
if (obj.endBlock) {
|
||||
obj.endBlock(obj);
|
||||
}
|
||||
}];
|
||||
};
|
||||
}];
|
||||
[self setAnimation:animationGroup params:params];
|
||||
return animationGroup;
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setAnimation:(CAAnimation *)animation params:(NSDictionary *)params {
|
||||
if (params[@"repeatCount"]) {
|
||||
NSInteger repeatCount = [params[@"repeatCount"] integerValue];
|
||||
if (repeatCount < 0) {
|
||||
repeatCount = NSNotFound;
|
||||
}
|
||||
animation.repeatCount = repeatCount;
|
||||
}
|
||||
if (params[@"repeatMode"]) {
|
||||
NSInteger repeatMode = [params[@"repeatMode"] integerValue];
|
||||
animation.autoreverses = repeatMode == 2;
|
||||
}
|
||||
|
||||
if (params[@"delay"]) {
|
||||
animation.beginTime = [params[@"delay"] floatValue] / 1000;
|
||||
}
|
||||
animation.duration = [params[@"duration"] floatValue] / 1000;
|
||||
}
|
||||
|
||||
- (void)setFillMode:(CAAnimation *)animation
|
||||
key:(NSString *)key
|
||||
startValue:(NSNumber *)startValue
|
||||
endValue:(NSNumber *)endValue
|
||||
fillMode:(NSNumber *)fillMode {
|
||||
NSUInteger fillModeInt = fillMode.unsignedIntegerValue;
|
||||
if ((fillModeInt & 2) == 2) {
|
||||
[self setAnimatedValue:key value:startValue];
|
||||
}
|
||||
AnimationCallback *callback = [AnimationCallback new];
|
||||
AnimationCallback *originCallback = animation.delegate;
|
||||
__weak typeof(self) _self = self;
|
||||
callback.startBlock = ^(AnimationCallback *callback) {
|
||||
__strong typeof(_self) self = _self;
|
||||
callback.dictionary[key] = [self getAnimatedValue:key];
|
||||
if (originCallback) {
|
||||
originCallback.startBlock(callback);
|
||||
}
|
||||
};
|
||||
callback.endBlock = ^(AnimationCallback *callback) {
|
||||
__strong typeof(_self) self = _self;
|
||||
if ((fillModeInt & 1) == 1) {
|
||||
[self setAnimatedValue:key value:endValue];
|
||||
}
|
||||
if (originCallback) {
|
||||
originCallback.endBlock(callback);
|
||||
}
|
||||
};
|
||||
animation.delegate = callback;
|
||||
}
|
||||
|
||||
- (NSNumber *)getAnimatedValue:(NSString *)key {
|
||||
if ([@"translationX" isEqualToString:key]) {
|
||||
return self.translationX;
|
||||
}
|
||||
if ([@"translationY" isEqualToString:key]) {
|
||||
return self.translationY;
|
||||
}
|
||||
if ([@"scaleX" isEqualToString:key]) {
|
||||
return self.scaleX;
|
||||
}
|
||||
if ([@"scaleY" isEqualToString:key]) {
|
||||
return self.scaleY;
|
||||
}
|
||||
if ([@"rotation" isEqualToString:key]) {
|
||||
return self.rotation;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setAnimatedValue:(NSString *)key value:(NSNumber *)value {
|
||||
if ([@"translationX" isEqualToString:key]) {
|
||||
self.translationX = value;
|
||||
} else if ([@"translationY" isEqualToString:key]) {
|
||||
self.translationY = value;
|
||||
} else if ([@"scaleX" isEqualToString:key]) {
|
||||
self.scaleX = value;
|
||||
} else if ([@"scaleY" isEqualToString:key]) {
|
||||
self.scaleY = value;
|
||||
} else if ([@"rotation" isEqualToString:key]) {
|
||||
self.rotation = value;
|
||||
}
|
||||
}
|
||||
|
||||
- (CABasicAnimation *)parseChangeable:(NSDictionary *)params fillMode:(NSNumber *)fillMode {
|
||||
NSString *key = params[@"key"];
|
||||
CABasicAnimation *animation = [CABasicAnimation animation];
|
||||
if ([@"scaleX" isEqualToString:key]) {
|
||||
animation.keyPath = @"transform.scale.x";
|
||||
animation.fromValue = params[@"fromValue"];
|
||||
animation.toValue = params[@"toValue"];
|
||||
} else if ([@"scaleY" isEqualToString:key]) {
|
||||
animation.keyPath = @"transform.scale.y";
|
||||
animation.fromValue = params[@"fromValue"];
|
||||
animation.toValue = params[@"toValue"];
|
||||
} else if ([@"rotation" isEqualToString:key]) {
|
||||
animation.keyPath = @"transform.rotation.z";
|
||||
animation.fromValue = @([params[@"fromValue"] floatValue] * M_PI);
|
||||
animation.toValue = @([params[@"toValue"] floatValue] * M_PI);
|
||||
} else if ([@"backgroundColor" isEqualToString:key]) {
|
||||
animation.keyPath = @"backgroundColor";
|
||||
animation.fromValue = params[@"fromValue"];
|
||||
animation.toValue = params[@"toValue"];
|
||||
}
|
||||
[self setFillMode:animation
|
||||
key:key
|
||||
startValue:params[@"fromValue"]
|
||||
endValue:params[@"toValue"]
|
||||
fillMode:fillMode];
|
||||
return animation;
|
||||
}
|
||||
|
||||
- (CAMediaTimingFunction *)translateToTimingFunction:(NSNumber *)timingFunction {
|
||||
switch (timingFunction.integerValue) {
|
||||
case 1:
|
||||
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
|
||||
case 2:
|
||||
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
|
||||
case 3:
|
||||
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
|
||||
case 4:
|
||||
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
|
||||
default:
|
||||
return [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionDefault];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
42
doric-iOS/Pod/Classes/Shader/UIView+Doric.h
Normal file
42
doric-iOS/Pod/Classes/Shader/UIView+Doric.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright [2019] [Doric.Pub]
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
//
|
||||
// UIView+Doric.h
|
||||
// Doric_Example
|
||||
//
|
||||
// Created by pengfei.zhou on 2019/7/25.
|
||||
// Copyright © 2019 CocoaPods. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIView.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface UIView (Doric)
|
||||
@property(nonatomic) CGFloat x;
|
||||
@property(nonatomic) CGFloat y;
|
||||
@property(nonatomic) CGFloat width;
|
||||
@property(nonatomic) CGFloat height;
|
||||
@property(nonatomic) CGFloat centerX;
|
||||
@property(nonatomic) CGFloat centerY;
|
||||
@property(nonatomic) CGFloat top;
|
||||
@property(nonatomic) CGFloat left;
|
||||
@property(nonatomic) CGFloat right;
|
||||
@property(nonatomic) CGFloat bottom;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user