1#import "RNCSafeAreaShadowView.h" 2 3#import <React/RCTAssert.h> 4#include <math.h> 5 6#import "RNCSafeAreaViewEdgeMode.h" 7#import "RNCSafeAreaViewEdges.h" 8#import "RNCSafeAreaViewLocalData.h" 9#import "RNCSafeAreaViewMode.h" 10 11// From RCTShadowView.m 12typedef NS_ENUM(unsigned int, meta_prop_t) { 13 META_PROP_LEFT, 14 META_PROP_TOP, 15 META_PROP_RIGHT, 16 META_PROP_BOTTOM, 17 META_PROP_HORIZONTAL, 18 META_PROP_VERTICAL, 19 META_PROP_ALL, 20 META_PROP_COUNT, 21}; 22 23@implementation RNCSafeAreaShadowView { 24 RNCSafeAreaViewLocalData *_localData; 25 bool _needsUpdate; 26 YGValue _paddingMetaProps[META_PROP_COUNT]; 27 YGValue _marginMetaProps[META_PROP_COUNT]; 28} 29 30- (instancetype)init 31{ 32 self = [super init]; 33 if (self) { 34 _needsUpdate = false; 35 for (unsigned int ii = 0; ii < META_PROP_COUNT; ii++) { 36 _paddingMetaProps[ii] = YGValueUndefined; 37 _marginMetaProps[ii] = YGValueUndefined; 38 } 39 } 40 return self; 41} 42 43- (void)extractEdges:(YGValue[])_metaProps 44 top:(CGFloat *)top 45 right:(CGFloat *)right 46 bottom:(CGFloat *)bottom 47 left:(CGFloat *)left 48{ 49 if (_metaProps[META_PROP_ALL].unit == YGUnitPoint) { 50 *top = _metaProps[META_PROP_ALL].value; 51 *right = _metaProps[META_PROP_ALL].value; 52 *bottom = _metaProps[META_PROP_ALL].value; 53 *left = _metaProps[META_PROP_ALL].value; 54 } 55 56 if (_metaProps[META_PROP_HORIZONTAL].unit == YGUnitPoint) { 57 *right = _metaProps[META_PROP_HORIZONTAL].value; 58 *left = _metaProps[META_PROP_HORIZONTAL].value; 59 } 60 61 if (_metaProps[META_PROP_VERTICAL].unit == YGUnitPoint) { 62 *top = _metaProps[META_PROP_VERTICAL].value; 63 *bottom = _metaProps[META_PROP_VERTICAL].value; 64 } 65 66 if (_metaProps[META_PROP_TOP].unit == YGUnitPoint) { 67 *top = _metaProps[META_PROP_TOP].value; 68 } 69 70 if (_metaProps[META_PROP_RIGHT].unit == YGUnitPoint) { 71 *right = _metaProps[META_PROP_RIGHT].value; 72 } 73 74 if (_metaProps[META_PROP_BOTTOM].unit == YGUnitPoint) { 75 *bottom = _metaProps[META_PROP_BOTTOM].value; 76 } 77 78 if (_metaProps[META_PROP_LEFT].unit == YGUnitPoint) { 79 *left = _metaProps[META_PROP_LEFT].value; 80 } 81} 82 83- (void)resetInsetsForMode:(RNCSafeAreaViewMode)mode 84{ 85 if (mode == RNCSafeAreaViewModePadding) { 86 super.paddingTop = _paddingMetaProps[META_PROP_TOP]; 87 super.paddingRight = _paddingMetaProps[META_PROP_RIGHT]; 88 super.paddingBottom = _paddingMetaProps[META_PROP_BOTTOM]; 89 super.paddingLeft = _paddingMetaProps[META_PROP_LEFT]; 90 } else if (mode == RNCSafeAreaViewModeMargin) { 91 super.marginTop = _marginMetaProps[META_PROP_TOP]; 92 super.marginRight = _marginMetaProps[META_PROP_RIGHT]; 93 super.marginBottom = _marginMetaProps[META_PROP_BOTTOM]; 94 super.marginLeft = _marginMetaProps[META_PROP_LEFT]; 95 } 96} 97 98- (void)updateInsets 99{ 100 if (_localData == nil) { 101 return; 102 } 103 104 UIEdgeInsets insets = _localData.insets; 105 RNCSafeAreaViewMode mode = _localData.mode; 106 RNCSafeAreaViewEdges edges = _localData.edges; 107 108 CGFloat top = 0; 109 CGFloat right = 0; 110 CGFloat bottom = 0; 111 CGFloat left = 0; 112 113 if (mode == RNCSafeAreaViewModePadding) { 114 [self extractEdges:_paddingMetaProps top:&top right:&right bottom:&bottom left:&left]; 115 super.paddingTop = (YGValue){[self getEdgeValue:edges.top insetValue:insets.top edgeValue:top], YGUnitPoint}; 116 super.paddingRight = 117 (YGValue){[self getEdgeValue:edges.right insetValue:insets.right edgeValue:right], YGUnitPoint}; 118 super.paddingBottom = 119 (YGValue){[self getEdgeValue:edges.bottom insetValue:insets.bottom edgeValue:bottom], YGUnitPoint}; 120 super.paddingLeft = (YGValue){[self getEdgeValue:edges.left insetValue:insets.left edgeValue:left], YGUnitPoint}; 121 } else if (mode == RNCSafeAreaViewModeMargin) { 122 [self extractEdges:_marginMetaProps top:&top right:&right bottom:&bottom left:&left]; 123 super.marginTop = (YGValue){[self getEdgeValue:edges.top insetValue:insets.top edgeValue:top], YGUnitPoint}; 124 super.marginRight = (YGValue){[self getEdgeValue:edges.right insetValue:insets.right edgeValue:right], YGUnitPoint}; 125 super.marginBottom = 126 (YGValue){[self getEdgeValue:edges.bottom insetValue:insets.bottom edgeValue:bottom], YGUnitPoint}; 127 super.marginLeft = (YGValue){[self getEdgeValue:edges.left insetValue:insets.left edgeValue:left], YGUnitPoint}; 128 } 129} 130 131- (CGFloat)getEdgeValue:(RNCSafeAreaViewEdgeMode)edgeMode insetValue:(CGFloat)insetValue edgeValue:(CGFloat)edgeValue 132{ 133 if (edgeMode == RNCSafeAreaViewEdgeModeOff) { 134 return edgeValue; 135 } else if (edgeMode == RNCSafeAreaViewEdgeModeMaximum) { 136 return MAX(insetValue, edgeValue); 137 } else { 138 return insetValue + edgeValue; 139 } 140} 141 142- (void)didSetProps:(NSArray<NSString *> *)changedProps 143{ 144 if (_needsUpdate) { 145 _needsUpdate = false; 146 [self updateInsets]; 147 } 148 [super didSetProps:changedProps]; 149} 150 151- (void)setLocalData:(RNCSafeAreaViewLocalData *)localData 152{ 153 RCTAssert( 154 [localData isKindOfClass:[RNCSafeAreaViewLocalData class]], 155 @"Local data object for `RCTRNCSafeAreaShadowView` must be `RCTRNCSafeAreaViewLocalData` instance."); 156 157 if (_localData != nil && _localData.mode != localData.mode) { 158 [self resetInsetsForMode:_localData.mode]; 159 } 160 161 _localData = localData; 162 _needsUpdate = false; 163 [self updateInsets]; 164 165 if (_localData.mode == RNCSafeAreaViewModePadding) { 166 [super didSetProps:@[ @"paddingTop", @"paddingRight", @"paddingBottom", @"paddingLeft" ]]; 167 } else { 168 [super didSetProps:@[ @"marginTop", @"marginRight", @"marginBottom", @"marginLeft" ]]; 169 } 170} 171 172#define SHADOW_VIEW_MARGIN_PADDING_PROP(edge, metaProp) \ 173 -(void)setPadding##edge : (YGValue)value \ 174 { \ 175 [super setPadding##edge:value]; \ 176 _needsUpdate = true; \ 177 _paddingMetaProps[META_PROP_##metaProp] = value; \ 178 } \ 179 -(void)setMargin##edge : (YGValue)value \ 180 { \ 181 [super setMargin##edge:value]; \ 182 _needsUpdate = true; \ 183 _marginMetaProps[META_PROP_##metaProp] = value; \ 184 } 185 186SHADOW_VIEW_MARGIN_PADDING_PROP(, ALL); 187SHADOW_VIEW_MARGIN_PADDING_PROP(Vertical, VERTICAL); 188SHADOW_VIEW_MARGIN_PADDING_PROP(Horizontal, HORIZONTAL); 189SHADOW_VIEW_MARGIN_PADDING_PROP(Top, TOP); 190SHADOW_VIEW_MARGIN_PADDING_PROP(Right, RIGHT); 191SHADOW_VIEW_MARGIN_PADDING_PROP(Bottom, BOTTOM); 192SHADOW_VIEW_MARGIN_PADDING_PROP(Left, LEFT); 193 194@end 195