Prepare skeleton parts for Custom Controls
This commit is contained in:
1 parent
dfdf2cd672
commit
3a80e5ce39
6 files changed
+161
-88
No files matched your search
@@ -13,7 +13,7 @@ set_target_properties(PojavLauncher PROPERTIES
|
||||
MACOSX_FRAMEWORK_IDENTIFIER org.cmake.ExecutableTarget
|
||||
MACOSX_BUNDLE_INFO_PLIST "../Info.plist")
|
||||
|
||||
add_library(pojavexec SHARED log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m egl_bridge.c input_bridge_v3.c utils.c)
|
||||
add_library(pojavexec SHARED log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m customcontrols/ControlButton.m egl_bridge.c input_bridge_v3.c utils.c)
|
||||
target_link_libraries(pojavexec
|
||||
"-Fresources/Frameworks"
|
||||
"-framework UIKit"
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#import "egl_bridge_ios.h"
|
||||
#import "ios_uikit_bridge.h"
|
||||
|
||||
#import "customcontrols/ControlButton.h"
|
||||
|
||||
#include "glfw_keycodes.h"
|
||||
#include "utils.h"
|
||||
|
||||
@@ -10,37 +12,27 @@
|
||||
#include "GLES2/gl2.h"
|
||||
#include "GLES2/gl2ext.h"
|
||||
|
||||
#define SPECIALBTN_KEYBOARD -1
|
||||
#define SPECIALBTN_TOGGLECTRL -2
|
||||
#define SPECIALBTN_MOUSEPRI -3
|
||||
#define SPECIALBTN_MOUSESEC -4
|
||||
#define SPECIALBTN_VIRTUALMOUSE -5
|
||||
#define SPECIALBTN_MOUSEMID -6
|
||||
#define SPECIALBTN_SCROLLUP -7
|
||||
#define SPECIALBTN_SCROLLDOWN -8
|
||||
|
||||
|
||||
// Debugging purposes
|
||||
// #define DEBUG_VISIBLE_TEXT_FIELD
|
||||
|
||||
#define ADD_BUTTON(NAME, KEY, RECT) \
|
||||
UIButton *button_##KEY = [UIButton buttonWithType:UIButtonTypeRoundedRect]; \
|
||||
button_##KEY.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth; \
|
||||
[button_##KEY setTitle:NAME forState:UIControlStateNormal]; \
|
||||
button_##KEY.frame = CGRectOffset(RECT, notchOffset, 0); \
|
||||
[button_##KEY addTarget:self action:@selector(executebtn_##KEY##_down) forControlEvents:UIControlEventTouchDown]; \
|
||||
[button_##KEY addTarget:self action:@selector(executebtn_##KEY##_up) forControlEvents:UIControlEventTouchUpInside]; \
|
||||
button_##KEY.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.3f]; \
|
||||
button_##KEY.tintColor = [UIColor whiteColor]; \
|
||||
[self.view addSubview:button_##KEY];
|
||||
|
||||
#define ADD_BUTTON_VISIBLE(NAME, KEY, RECT) \
|
||||
ADD_BUTTON(NAME, KEY, RECT); \
|
||||
togglableVisibleButtons[++togglableVisibleButtonIndex] = button_##KEY;
|
||||
|
||||
|
||||
#define ADD_BUTTON_DEF(KEY) \
|
||||
- (void)executebtn_##KEY##_down { \
|
||||
[self executebtn_##KEY:1]; \
|
||||
} \
|
||||
- (void)executebtn_##KEY##_up { \
|
||||
[self executebtn_##KEY:0]; \
|
||||
} \
|
||||
- (void)executebtn_##KEY:(int)held
|
||||
|
||||
#define ADD_BUTTON_DEF_KEY(KEY, KEYCODE) \
|
||||
ADD_BUTTON_DEF(KEY) { \
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, KEYCODE, 0, held, 0); \
|
||||
#define ADD_BUTTON(NAME, KEY, RECT, VISIBLE) \
|
||||
ControlButton *button_##KEY = [ControlButton initWithName:NAME keycode:KEY rect:CGRectOffset(RECT, notchOffset, 0) transparency:0.0f]; \
|
||||
[button_##KEY addTarget:self action:@selector(executebtn_down:) forControlEvents:UIControlEventTouchDown]; \
|
||||
[button_##KEY addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpInside]; \
|
||||
[button_##KEY addTarget:self action:@selector(executebtn_up:) forControlEvents:UIControlEventTouchUpOutside]; \
|
||||
[self.view addSubview:button_##KEY]; \
|
||||
if (VISIBLE == YES) { \
|
||||
togglableVisibleButtons[++togglableVisibleButtonIndex] = button_##KEY; \
|
||||
}
|
||||
|
||||
#define BTN_RECT 80.0, 30.0
|
||||
@@ -49,7 +41,7 @@
|
||||
#define INPUT_SPACE_LENGTH 20
|
||||
|
||||
int togglableVisibleButtonIndex = -1;
|
||||
UIButton* togglableVisibleButtons[100];
|
||||
ControlButton* togglableVisibleButtons[100];
|
||||
|
||||
UIView *touchView;
|
||||
#ifdef DEBUG_VISIBLE_TEXT_FIELD
|
||||
@@ -139,31 +131,31 @@ int notchOffset;
|
||||
// Custom button
|
||||
// ADD_BUTTON(@"F1", f1, CGRectMake(5, 5, width, height));
|
||||
|
||||
ADD_BUTTON(@"GUI", special_togglebtn, CGRectMake(5, height - 5 - 50, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"Keyboard", special_keyboard, CGRectMake(5 * 3 + 80 * 2, 5, BTN_RECT));
|
||||
ADD_BUTTON(@"GUI", SPECIALBTN_TOGGLECTRL, CGRectMake(5, height - 5 - 50, BTN_SQUARE), NO);
|
||||
ADD_BUTTON(@"Keyboard", SPECIALBTN_KEYBOARD, CGRectMake(5 * 3 + 80 * 2, 5, BTN_RECT), YES);
|
||||
|
||||
ADD_BUTTON_VISIBLE(@"Pri", special_mouse_pri, CGRectMake(5, height - 5 * 3 - 50 * 3, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"Sec", special_mouse_sec, CGRectMake(5 * 3 + 50 * 2, height - 5 * 3 - 50 * 3, BTN_SQUARE));
|
||||
ADD_BUTTON(@"Pri", SPECIALBTN_MOUSEPRI, CGRectMake(5, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"Sec", SPECIALBTN_MOUSESEC, CGRectMake(5 * 3 + 50 * 2, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
||||
|
||||
ADD_BUTTON_VISIBLE(@"Debug", f3, CGRectMake(5, 5, BTN_RECT));
|
||||
ADD_BUTTON_VISIBLE(@"Chat", t, CGRectMake(5 * 2 + 80, 5, BTN_RECT));
|
||||
ADD_BUTTON_VISIBLE(@"Tab", tab, CGRectMake(5 * 4 + 80 * 3, 5, BTN_RECT));
|
||||
ADD_BUTTON_VISIBLE(@"Opti-Zoom", c, CGRectMake(5 * 5 + 80 * 4, 5, BTN_RECT));
|
||||
ADD_BUTTON_VISIBLE(@"Offhand", f, CGRectMake(5 * 6 + 80 * 5, 5, BTN_RECT));
|
||||
ADD_BUTTON_VISIBLE(@"3rd", f5, CGRectMake(5, 5 * 2 + 30.0, BTN_RECT));
|
||||
ADD_BUTTON(@"Debug", GLFW_KEY_F3, CGRectMake(5, 5, BTN_RECT), YES);
|
||||
ADD_BUTTON(@"Chat", GLFW_KEY_T, CGRectMake(5 * 2 + 80, 5, BTN_RECT), YES);
|
||||
ADD_BUTTON(@"Tab", GLFW_KEY_TAB, CGRectMake(5 * 4 + 80 * 3, 5, BTN_RECT), YES);
|
||||
ADD_BUTTON(@"Opti-Zoom", GLFW_KEY_C, CGRectMake(5 * 5 + 80 * 4, 5, BTN_RECT), YES);
|
||||
ADD_BUTTON(@"Offhand", GLFW_KEY_F, CGRectMake(5 * 6 + 80 * 5, 5, BTN_RECT), YES);
|
||||
ADD_BUTTON(@"3rd", GLFW_KEY_F5, CGRectMake(5, 5 * 2 + 30.0, BTN_RECT), YES);
|
||||
|
||||
ADD_BUTTON_VISIBLE(@"▲", w, CGRectMake(5 * 2 + 50, height - 5 * 3 - 50 * 3, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"◀", a, CGRectMake(5, height - 5 * 2 - 50 * 2, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"▼", s, CGRectMake(5 * 2 + 50, height - 5 - 50, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"▶", d, CGRectMake(5 * 3 + 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"◇", left_shift, CGRectMake(5 * 2 + 50, height - 5 * 2 - 50 * 2, BTN_SQUARE));
|
||||
ADD_BUTTON_VISIBLE(@"Inv", e, CGRectMake(5 * 3 + 50 * 2, height - 5 - 50, BTN_SQUARE));
|
||||
ADD_BUTTON(@"▲", GLFW_KEY_W, CGRectMake(5 * 2 + 50, height - 5 * 3 - 50 * 3, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"◀", GLFW_KEY_A, CGRectMake(5, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"▼", GLFW_KEY_S, CGRectMake(5 * 2 + 50, height - 5 - 50, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"▶", GLFW_KEY_D, CGRectMake(5 * 3 + 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"◇", GLFW_KEY_LEFT_SHIFT, CGRectMake(5 * 2 + 50, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
||||
ADD_BUTTON(@"Inv", GLFW_KEY_E, CGRectMake(5 * 3 + 50 * 2, height - 5 - 50, BTN_SQUARE), YES);
|
||||
|
||||
ADD_BUTTON_VISIBLE(@"⬛", space, CGRectMake(width - 5 * 2 - 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE));
|
||||
ADD_BUTTON(@"⬛", GLFW_KEY_SPACE, CGRectMake(width - 5 * 2 - 50 * 2, height - 5 * 2 - 50 * 2, BTN_SQUARE), YES);
|
||||
|
||||
ADD_BUTTON_VISIBLE(@"Esc", escape, CGRectMake(width - 5 - 80, height - 5 - 30, BTN_RECT));
|
||||
ADD_BUTTON(@"Esc", GLFW_KEY_ESCAPE, CGRectMake(width - 5 - 80, height - 5 - 30, BTN_RECT), YES);
|
||||
|
||||
// ADD_BUTTON_VISIBLE(@"Fullscreen", f11, CGRectMake(width - 5 - 80, 5, BTN_RECT));
|
||||
// ADD_BUTTON(@"Fullscreen", f11, CGRectMake(width - 5 - 80, 5, BTN_RECT), YES);
|
||||
|
||||
[self.view addSubview:inputView];
|
||||
|
||||
@@ -282,7 +274,9 @@ BOOL isNotifRemoved;
|
||||
} else ++touchesMovedCount;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
} else if (@available(iOS 13.4, *)) {
|
||||
// Recheck @available for fix compile warnings
|
||||
|
||||
// Mouse clicks are handled here
|
||||
int held = event == ACTION_MOVE || event == ACTION_UP;
|
||||
shouldTriggerClick = NO;
|
||||
@@ -521,7 +515,50 @@ NSString* inputStringBefore;
|
||||
#pragma mark - On-screen button functions
|
||||
|
||||
int currentVisibility = 1;
|
||||
ADD_BUTTON_DEF(special_togglebtn) {
|
||||
- (void) executebtn:(UIButton *)sender withAction:(int)action {
|
||||
ControlButton *button = (ControlButton *)sender;
|
||||
int held = action == ACTION_DOWN;
|
||||
int keycode = [(NSNumber *) [button.properties valueForKey:@"keycode"] intValue];
|
||||
if (keycode < 0) {
|
||||
switch (keycode) {
|
||||
case SPECIALBTN_KEYBOARD:
|
||||
if (held == 0) {
|
||||
[inputView resignFirstResponder];
|
||||
inputView.alpha = 1.0f;
|
||||
inputView.text = @"";
|
||||
}
|
||||
break;
|
||||
|
||||
case SPECIALBTN_MOUSEPRI:
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, held, 0);
|
||||
break;
|
||||
|
||||
case SPECIALBTN_MOUSESEC:
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_RIGHT, held, 0);
|
||||
break;
|
||||
|
||||
case SPECIALBTN_MOUSEMID:
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_MIDDLE, held, 0);
|
||||
break;
|
||||
|
||||
case SPECIALBTN_TOGGLECTRL:
|
||||
[self executebtn_special_togglebtn:held];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendKey(NULL, NULL, keycode, 0, held, 0);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) executebtn_down:(UIButton *)sender {
|
||||
[self executebtn:sender withAction:ACTION_DOWN];
|
||||
}
|
||||
|
||||
- (void) executebtn_up:(UIButton *)sender {
|
||||
[self executebtn:sender withAction:ACTION_UP];
|
||||
}
|
||||
|
||||
- (void) executebtn_special_togglebtn:(int)held {
|
||||
if (held == 0) {
|
||||
currentVisibility = !currentVisibility;
|
||||
for (int i = 0; i < togglableVisibleButtonIndex + 1; i++) {
|
||||
@@ -534,41 +571,6 @@ ADD_BUTTON_DEF(special_togglebtn) {
|
||||
}
|
||||
}
|
||||
|
||||
ADD_BUTTON_DEF(special_keyboard) {
|
||||
if (held == 0) {
|
||||
[inputView resignFirstResponder];
|
||||
inputView.alpha = 1.0f;
|
||||
inputView.text = @"";
|
||||
}
|
||||
}
|
||||
|
||||
ADD_BUTTON_DEF(special_mouse_pri) {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_LEFT, held, 0);
|
||||
}
|
||||
|
||||
ADD_BUTTON_DEF(special_mouse_sec) {
|
||||
Java_org_lwjgl_glfw_CallbackBridge_nativeSendMouseButton(NULL, NULL, GLFW_MOUSE_BUTTON_RIGHT, held, 0);
|
||||
}
|
||||
|
||||
ADD_BUTTON_DEF_KEY(f3, GLFW_KEY_F3)
|
||||
ADD_BUTTON_DEF_KEY(f5, GLFW_KEY_F5)
|
||||
ADD_BUTTON_DEF_KEY(f11, GLFW_KEY_F11)
|
||||
ADD_BUTTON_DEF_KEY(t, GLFW_KEY_T)
|
||||
ADD_BUTTON_DEF_KEY(c, GLFW_KEY_C)
|
||||
ADD_BUTTON_DEF_KEY(f, GLFW_KEY_F)
|
||||
ADD_BUTTON_DEF_KEY(tab, GLFW_KEY_TAB)
|
||||
|
||||
ADD_BUTTON_DEF_KEY(w, GLFW_KEY_W)
|
||||
ADD_BUTTON_DEF_KEY(a, GLFW_KEY_A)
|
||||
ADD_BUTTON_DEF_KEY(s, GLFW_KEY_S)
|
||||
ADD_BUTTON_DEF_KEY(d, GLFW_KEY_D)
|
||||
ADD_BUTTON_DEF_KEY(e, GLFW_KEY_E)
|
||||
|
||||
ADD_BUTTON_DEF_KEY(left_shift, GLFW_KEY_LEFT_SHIFT)
|
||||
|
||||
ADD_BUTTON_DEF_KEY(space, GLFW_KEY_SPACE)
|
||||
ADD_BUTTON_DEF_KEY(escape, GLFW_KEY_ESCAPE)
|
||||
|
||||
#pragma mark - Input: On-screen touch events
|
||||
|
||||
int touchesMovedCount;
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# This one is only used for local compile on developer iphone, do not execute!
|
||||
# This one is only used for local compile on developer iphone, do not execute if
|
||||
# - You don't know what will it does.
|
||||
# - No SDK and clang installed.
|
||||
|
||||
#!/bin/bash
|
||||
set -e
|
||||
@@ -6,7 +8,7 @@ set -e
|
||||
CFLAGS="-fmessage-length=0 -fdiagnostics-show-note-include-stack -fmacro-backtrace-limit=0 -Wno-trigraphs -fpascal-strings -O3 -Wno-missing-field-initializers -Wno-missing-prototypes -Wno-return-type -Wno-missing-braces -Wparentheses -Wswitch -Wno-unused-function -Wno-unused-label -Wno-unused-parameter -Wno-unused-variable -Wunused-value -Wno-empty-body -Wno-uninitialized -Wno-unknown-pragmas -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wno-constant-conversion -Wno-int-conversion -Wno-bool-conversion -Wno-enum-conversion -Wno-float-conversion -Wno-non-literal-null-conversion -Wno-objc-literal-conversion -Wshorten-64-to-32 -Wpointer-sign -Wno-newline-eof -Wl,-rpath,/Applications/PojavLauncher.app/Frameworks -fobjc-arc -x objective-c -Fresources/Frameworks -Iresources/Frameworks/MetalANGLE.framework/Headers -isysroot /var/mobile/theos/sdks/iPhoneOS13.4.sdk"
|
||||
|
||||
clang -framework UIKit $CFLAGS -o PojavLauncher main.c log.m JavaLauncher.c
|
||||
clang -framework UIKit -framework MetalANGLE -framework CoreGraphics -framework AuthenticationServices -dynamiclib $CFLAGS -o libpojavexec.dylib log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m egl_bridge.c input_bridge_v3.c utils.c -DGLES_TESTZ -DUSE_EGLZ -Wl,-undefined,dynamic_lookup
|
||||
clang -framework UIKit -framework MetalANGLE -framework CoreGraphics -framework AuthenticationServices -dynamiclib $CFLAGS -o libpojavexec.dylib log.m AppDelegate.m SceneDelegate.m UILauncher.m LauncherViewController.m LoginViewController.m SurfaceViewController.m egl_bridge_ios.m ios_uikit_bridge.m customcontrols/ControlButton.m egl_bridge.c input_bridge_v3.c utils.c -DGLES_TESTZ -DUSE_EGLZ -Wl,-undefined,dynamic_lookup
|
||||
|
||||
ldid -S../entitlements.xml PojavLauncher
|
||||
ldid -S../entitlements.xml libpojavexec.dylib
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
/**
|
||||
* Custom controls have same format as Android.
|
||||
*
|
||||
* Android - iOS:
|
||||
* ControlButton - same
|
||||
* ControlData - NSArray with JSON components
|
||||
*/
|
||||
|
||||
@interface ControlButton : UIButton {
|
||||
NSMutableDictionary* properties;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSMutableDictionary* properties;
|
||||
|
||||
+ (id)initWithProperties:(NSMutableDictionary *)propArray;
|
||||
+ (id)initWithName:(NSString *)name keycode:(int)keycode rect:(CGRect)rect transparency:(float)transparency;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,49 @@
|
||||
#import "ControlButton.h"
|
||||
|
||||
#define NUM2F(x) [(NSNumber *)x floatValue]
|
||||
|
||||
@implementation ControlButton
|
||||
@synthesize properties;
|
||||
|
||||
/**
|
||||
* To compatible with Android, NSArray (ControlData)
|
||||
* will store the scaled values.
|
||||
*/
|
||||
|
||||
+ (id)initWithProperties:(NSMutableDictionary *)propArray {
|
||||
float screenScale = (float) [[UIScreen mainScreen] scale];
|
||||
|
||||
float propX = NUM2F([propArray valueForKey:@"x"]) / screenScale;
|
||||
float propY = NUM2F([propArray valueForKey:@"y"]) / screenScale;
|
||||
float propW = NUM2F([propArray valueForKey:@"width"]) / screenScale;
|
||||
float propH = NUM2F([propArray valueForKey:@"height"]) / screenScale;
|
||||
ControlButton *instance = [ControlButton buttonWithType:UIButtonTypeRoundedRect];
|
||||
[instance setTitle:[propArray valueForKey:@"name"]
|
||||
forState:UIControlStateNormal];
|
||||
instance.frame = CGRectMake(propX, propY, propW, propH);
|
||||
instance.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||
|
||||
instance.alpha = 1.0f - NUM2F([propArray valueForKey:@"transparency"]) / 100.0f;
|
||||
instance.backgroundColor = [UIColor colorWithWhite:0.0f alpha:0.3f];
|
||||
instance.tintColor = [UIColor whiteColor];
|
||||
|
||||
instance.properties = propArray;
|
||||
return instance;
|
||||
}
|
||||
|
||||
+ (id)initWithName:(NSString *)name keycode:(int)keycode rect:(CGRect)rect transparency:(float)transparency {
|
||||
float screenScale = (float) [[UIScreen mainScreen] scale];
|
||||
|
||||
NSMutableDictionary *properties = [[NSMutableDictionary alloc] init];
|
||||
[properties setObject:name forKey:@"name"];
|
||||
[properties setObject:@(rect.origin.x * screenScale) forKey:@"x"];
|
||||
[properties setObject:@(rect.origin.y * screenScale) forKey:@"y"];
|
||||
[properties setObject:@(rect.size.width * screenScale) forKey:@"width"];
|
||||
[properties setObject:@(rect.size.height * screenScale) forKey:@"height"];
|
||||
[properties setObject:@(keycode) forKey:@"keycode"];
|
||||
[properties setObject:@(transparency) forKey:@"transparency"];
|
||||
|
||||
return [ControlButton initWithProperties:properties];
|
||||
}
|
||||
|
||||
@end
|
||||
Binary file not shown.
Reference in new issue
Block a user