This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.1 KiB
281 lines
7.1 KiB
/** |
|
* Copyright (c) 2015-present, Facebook, Inc. |
|
* |
|
* This source code is licensed under the MIT license found in the |
|
* LICENSE file in the root directory of this source tree. |
|
*/ |
|
|
|
#import "UIView+React.h" |
|
|
|
#import <objc/runtime.h> |
|
|
|
#import "RCTAssert.h" |
|
#import "RCTLog.h" |
|
#import "RCTShadowView.h" |
|
|
|
@implementation UIView (React) |
|
|
|
- (NSNumber *)reactTag |
|
{ |
|
return objc_getAssociatedObject(self, _cmd); |
|
} |
|
|
|
- (void)setReactTag:(NSNumber *)reactTag |
|
{ |
|
objc_setAssociatedObject(self, @selector(reactTag), reactTag, OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
|
} |
|
|
|
- (NSNumber *)nativeID |
|
{ |
|
return objc_getAssociatedObject(self, _cmd); |
|
} |
|
|
|
- (void)setNativeID:(NSNumber *)nativeID |
|
{ |
|
objc_setAssociatedObject(self, @selector(nativeID), nativeID, OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
|
} |
|
|
|
- (BOOL)isReactRootView |
|
{ |
|
return RCTIsReactRootView(self.reactTag); |
|
} |
|
|
|
- (NSNumber *)reactTagAtPoint:(CGPoint)point |
|
{ |
|
UIView *view = [self hitTest:point withEvent:nil]; |
|
while (view && !view.reactTag) { |
|
view = view.superview; |
|
} |
|
return view.reactTag; |
|
} |
|
|
|
- (NSArray<UIView *> *)reactSubviews |
|
{ |
|
return objc_getAssociatedObject(self, _cmd); |
|
} |
|
|
|
- (UIView *)reactSuperview |
|
{ |
|
return self.superview; |
|
} |
|
|
|
- (void)insertReactSubview:(UIView *)subview atIndex:(NSInteger)atIndex |
|
{ |
|
// We access the associated object directly here in case someone overrides |
|
// the `reactSubviews` getter method and returns an immutable array. |
|
NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(reactSubviews)); |
|
if (!subviews) { |
|
subviews = [NSMutableArray new]; |
|
objc_setAssociatedObject(self, @selector(reactSubviews), subviews, OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
|
} |
|
[subviews insertObject:subview atIndex:atIndex]; |
|
} |
|
|
|
- (void)removeReactSubview:(UIView *)subview |
|
{ |
|
// We access the associated object directly here in case someone overrides |
|
// the `reactSubviews` getter method and returns an immutable array. |
|
NSMutableArray *subviews = objc_getAssociatedObject(self, @selector(reactSubviews)); |
|
[subviews removeObject:subview]; |
|
[subview removeFromSuperview]; |
|
} |
|
|
|
#pragma mark - Display |
|
|
|
- (YGDisplay)reactDisplay |
|
{ |
|
return self.isHidden ? YGDisplayNone : YGDisplayFlex; |
|
} |
|
|
|
- (void)setReactDisplay:(YGDisplay)display |
|
{ |
|
self.hidden = display == YGDisplayNone; |
|
} |
|
|
|
#pragma mark - Layout Direction |
|
|
|
- (UIUserInterfaceLayoutDirection)reactLayoutDirection |
|
{ |
|
if ([self respondsToSelector:@selector(semanticContentAttribute)]) { |
|
return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.semanticContentAttribute]; |
|
} else { |
|
return [objc_getAssociatedObject(self, @selector(reactLayoutDirection)) integerValue]; |
|
} |
|
} |
|
|
|
- (void)setReactLayoutDirection:(UIUserInterfaceLayoutDirection)layoutDirection |
|
{ |
|
if ([self respondsToSelector:@selector(setSemanticContentAttribute:)]) { |
|
self.semanticContentAttribute = |
|
layoutDirection == UIUserInterfaceLayoutDirectionLeftToRight ? |
|
UISemanticContentAttributeForceLeftToRight : |
|
UISemanticContentAttributeForceRightToLeft; |
|
} else { |
|
objc_setAssociatedObject(self, @selector(reactLayoutDirection), @(layoutDirection), OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
|
} |
|
} |
|
|
|
#pragma mark - zIndex |
|
|
|
- (NSInteger)reactZIndex |
|
{ |
|
return self.layer.zPosition; |
|
} |
|
|
|
- (void)setReactZIndex:(NSInteger)reactZIndex |
|
{ |
|
self.layer.zPosition = reactZIndex; |
|
} |
|
|
|
- (NSArray<UIView *> *)reactZIndexSortedSubviews |
|
{ |
|
// Check if sorting is required - in most cases it won't be. |
|
BOOL sortingRequired = NO; |
|
for (UIView *subview in self.subviews) { |
|
if (subview.reactZIndex != 0) { |
|
sortingRequired = YES; |
|
break; |
|
} |
|
} |
|
return sortingRequired ? [self.reactSubviews sortedArrayUsingComparator:^NSComparisonResult(UIView *a, UIView *b) { |
|
if (a.reactZIndex > b.reactZIndex) { |
|
return NSOrderedDescending; |
|
} else { |
|
// Ensure sorting is stable by treating equal zIndex as ascending so |
|
// that original order is preserved. |
|
return NSOrderedAscending; |
|
} |
|
}] : self.subviews; |
|
} |
|
|
|
- (void)didUpdateReactSubviews |
|
{ |
|
for (UIView *subview in self.reactSubviews) { |
|
[self addSubview:subview]; |
|
} |
|
} |
|
|
|
- (void)didSetProps:(__unused NSArray<NSString *> *)changedProps |
|
{ |
|
// The default implementation does nothing. |
|
} |
|
|
|
- (void)reactSetFrame:(CGRect)frame |
|
{ |
|
// These frames are in terms of anchorPoint = topLeft, but internally the |
|
// views are anchorPoint = center for easier scale and rotation animations. |
|
// Convert the frame so it works with anchorPoint = center. |
|
CGPoint position = {CGRectGetMidX(frame), CGRectGetMidY(frame)}; |
|
CGRect bounds = {CGPointZero, frame.size}; |
|
|
|
// Avoid crashes due to nan coords |
|
if (isnan(position.x) || isnan(position.y) || |
|
isnan(bounds.origin.x) || isnan(bounds.origin.y) || |
|
isnan(bounds.size.width) || isnan(bounds.size.height)) { |
|
RCTLogError(@"Invalid layout for (%@)%@. position: %@. bounds: %@", |
|
self.reactTag, self, NSStringFromCGPoint(position), NSStringFromCGRect(bounds)); |
|
return; |
|
} |
|
|
|
self.center = position; |
|
self.bounds = bounds; |
|
} |
|
|
|
- (UIViewController *)reactViewController |
|
{ |
|
id responder = [self nextResponder]; |
|
while (responder) { |
|
if ([responder isKindOfClass:[UIViewController class]]) { |
|
return responder; |
|
} |
|
responder = [responder nextResponder]; |
|
} |
|
return nil; |
|
} |
|
|
|
- (void)reactAddControllerToClosestParent:(UIViewController *)controller |
|
{ |
|
if (!controller.parentViewController) { |
|
UIView *parentView = (UIView *)self.reactSuperview; |
|
while (parentView) { |
|
if (parentView.reactViewController) { |
|
[parentView.reactViewController addChildViewController:controller]; |
|
[controller didMoveToParentViewController:parentView.reactViewController]; |
|
break; |
|
} |
|
parentView = (UIView *)parentView.reactSuperview; |
|
} |
|
return; |
|
} |
|
} |
|
|
|
/** |
|
* Focus manipulation. |
|
*/ |
|
- (BOOL)reactIsFocusNeeded |
|
{ |
|
return [(NSNumber *)objc_getAssociatedObject(self, @selector(reactIsFocusNeeded)) boolValue]; |
|
} |
|
|
|
- (void)setReactIsFocusNeeded:(BOOL)isFocusNeeded |
|
{ |
|
objc_setAssociatedObject(self, @selector(reactIsFocusNeeded), @(isFocusNeeded), OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
|
} |
|
|
|
- (void)reactFocus { |
|
if (![self becomeFirstResponder]) { |
|
self.reactIsFocusNeeded = YES; |
|
} |
|
} |
|
|
|
- (void)reactFocusIfNeeded { |
|
if (self.reactIsFocusNeeded) { |
|
if ([self becomeFirstResponder]) { |
|
self.reactIsFocusNeeded = NO; |
|
} |
|
} |
|
} |
|
|
|
- (void)reactBlur { |
|
[self resignFirstResponder]; |
|
} |
|
|
|
#pragma mark - Layout |
|
|
|
- (UIEdgeInsets)reactBorderInsets |
|
{ |
|
CGFloat borderWidth = self.layer.borderWidth; |
|
return UIEdgeInsetsMake(borderWidth, borderWidth, borderWidth, borderWidth); |
|
} |
|
|
|
- (UIEdgeInsets)reactPaddingInsets |
|
{ |
|
return UIEdgeInsetsZero; |
|
} |
|
|
|
- (UIEdgeInsets)reactCompoundInsets |
|
{ |
|
UIEdgeInsets borderInsets = self.reactBorderInsets; |
|
UIEdgeInsets paddingInsets = self.reactPaddingInsets; |
|
|
|
return UIEdgeInsetsMake( |
|
borderInsets.top + paddingInsets.top, |
|
borderInsets.left + paddingInsets.left, |
|
borderInsets.bottom + paddingInsets.bottom, |
|
borderInsets.right + paddingInsets.right |
|
); |
|
} |
|
|
|
- (CGRect)reactContentFrame |
|
{ |
|
return UIEdgeInsetsInsetRect(self.bounds, self.reactCompoundInsets); |
|
} |
|
|
|
#pragma mark - Accessiblity |
|
|
|
- (UIView *)reactAccessibilityElement |
|
{ |
|
return self; |
|
} |
|
|
|
@end
|
|
|