Skip to content

Commit

Permalink
Update Material iOS to compile for visionOS
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 641364760
  • Loading branch information
Nobody authored and material-automation committed Jun 7, 2024
1 parent 100bbde commit 8f69468
Show file tree
Hide file tree
Showing 16 changed files with 236 additions and 3 deletions.
11 changes: 11 additions & 0 deletions components/AppBar/src/MDCAppBarNavigationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@

#import <objc/runtime.h>

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

// Light-weight book-keeping associated with any pushed view controller.
@interface MDCAppBarNavigationControllerInfo : NSObject

Expand Down Expand Up @@ -111,7 +118,9 @@ - (void)pushViewController:(UIViewController *)viewController animated:(BOOL)ani

[self injectAppBarIntoViewController:viewController];

#if !IS_VISIONOS
[self setNeedsStatusBarAppearanceUpdate];
#endif
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}

Expand All @@ -122,7 +131,9 @@ - (void)setViewControllers:(NSArray<UIViewController *> *)viewControllers animat
[self injectAppBarIntoViewController:viewController];
}

#if !IS_VISIONOS
[self setNeedsStatusBarAppearanceUpdate];
#endif
[self setNeedsUpdateOfHomeIndicatorAutoHidden];
}

Expand Down
14 changes: 14 additions & 0 deletions components/Buttons/src/MDCButton.m
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,13 @@
#import "UIFont+MaterialTypography.h"
#import "MDCMath.h"

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

// TODO(ajsecord): Animate title color when animating between enabled/disabled states.
// Non-trivial: http://corecocoa.wordpress.com/2011/10/04/animatable-text-color-of-uilabel/

Expand Down Expand Up @@ -373,7 +380,14 @@ - (void)layoutSubviews {
_inkView.frame = bounds;
self.rippleView.frame = bounds;
}

#if IS_VISIONOS
UITraitCollection *current = [UITraitCollection currentTraitCollection];
self.titleLabel.frame =
MDCRectAlignToScale(self.titleLabel.frame, current ? [current displayScale] : 1.0);
#else
self.titleLabel.frame = MDCRectAlignToScale(self.titleLabel.frame, [UIScreen mainScreen].scale);
#endif

if ([self shouldInferMinimumAndMaximumSize]) {
[self inferMinimumAndMaximumSize];
Expand Down
17 changes: 17 additions & 0 deletions components/CollectionCells/src/MDCCollectionViewTextCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@

#include <tgmath.h>

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

// Default cell heights.
const CGFloat MDCCellDefaultOneLineHeight = 48;
const CGFloat MDCCellDefaultOneLineWithAvatarHeight = 56;
Expand Down Expand Up @@ -61,14 +68,24 @@ static inline CGFloat CellDefaultDetailTextFontOpacity(void) {
// Returns the closest pixel-aligned value higher than |value|, taking the scale factor into
// account. At a scale of 1, equivalent to Ceil().
static inline CGFloat AlignValueToUpperPixel(CGFloat value) {
#if !IS_VISIONOS
CGFloat scale = [[UIScreen mainScreen] scale];
#else
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
#endif
return (CGFloat)ceil(value * scale) / scale;
}

// Returns the closest pixel-aligned value lower than |value|, taking the scale factor into
// account. At a scale of 1, equivalent to Floor().
static inline CGFloat AlignValueToLowerPixel(CGFloat value) {
#if !IS_VISIONOS
CGFloat scale = [[UIScreen mainScreen] scale];
#else
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
#endif
return (CGFloat)floor(value * scale) / scale;
}

Expand Down
7 changes: 7 additions & 0 deletions components/Collections/src/private/MDCCollectionInfoBarView.m
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,14 @@ - (void)setStyle:(MDCCollectionInfoBarViewStyle)style {
if (!_backgroundBorderLayer) {
_backgroundBorderLayer = [CALayer layer];
_backgroundBorderLayer.borderColor = [UIColor colorWithWhite:0 alpha:(CGFloat)0.1].CGColor;
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
_backgroundBorderLayer.borderWidth = 1 / scale;
#else
_backgroundBorderLayer.borderWidth = 1 / [[UIScreen mainScreen] scale];
#endif
[self.backgroundView.layer addSublayer:_backgroundBorderLayer];
}
}
Expand Down
7 changes: 7 additions & 0 deletions components/Collections/src/private/MDCCollectionViewEditor.m
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,14 @@ - (UIImage *)snapshotWithRect:(CGRect)rect {

// Render snapshot.
[_collectionView.layer renderInContext:cx];
#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
_collectionView.layer.rasterizationScale = scale;
#else
_collectionView.layer.rasterizationScale = [UIScreen mainScreen].scale;
#endif
_collectionView.layer.shouldRasterize = YES;
UIImage *screenshotImage = UIGraphicsGetImageFromCurrentImageContext();

Expand Down
27 changes: 27 additions & 0 deletions components/Collections/src/private/MDCCollectionViewStyler.m
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@

#include <tgmath.h>

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

typedef NS_OPTIONS(NSUInteger, BackgroundCacheKey) {
BackgroundCacheKeyFlat = 0,
BackgroundCacheKeyTop = 1 << 0,
Expand Down Expand Up @@ -133,8 +140,16 @@ - (instancetype)initWithCollectionView:(UICollectionView *)collectionView {
// Cell separator defaults.
_separatorColor = MDCPalette.greyPalette.tint300;
_separatorInset = UIEdgeInsetsZero;

#if IS_VISIONOS
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
_separatorLineHeight = kCollectionViewCellSeparatorDefaultHeightInPixels / scale;
#else
_separatorLineHeight =
kCollectionViewCellSeparatorDefaultHeightInPixels / [[UIScreen mainScreen] scale];
#endif

_shouldHideSeparators = NO;

// Grid defaults.
Expand Down Expand Up @@ -301,7 +316,13 @@ - (UIEdgeInsets)backgroundImageViewOutsetsForCellWithAttribute:
if ([self drawShadowForCellWithIsCardStye:isCardStyle
isGroupStyle:isGroupedStyle
isHighlighted:isHighlighted]) {
#if IS_VISIONOS
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
CGFloat mainScreenScale = scale;
#else
CGFloat mainScreenScale = [[UIScreen mainScreen] scale];
#endif
if (mainScreenScale > (CGFloat)2.1) {
insets = kCollectionViewCellContentInsetsRetina3x;
} else if (mainScreenScale > (CGFloat)1.1) {
Expand Down Expand Up @@ -680,7 +701,13 @@ - (UIImage *)backgroundImageForCellLayoutAttributes:(MDCCollectionViewLayoutAttr
// We want to draw the borders and shadows on single retina-pixel boundaries if possible, but
// we need to avoid doing this on non-retina devices because it'll look blurry.
- (CGFloat)minPixelOffset {
#if IS_VISIONOS
UITraitCollection *current = [UITraitCollection currentTraitCollection];
CGFloat scale = current ? [current displayScale] : 1.0;
return 1 / scale;
#else
return 1 / [[UIScreen mainScreen] scale];
#endif
}

- (UIImage *)resizableImage:(UIImage *)image {
Expand Down
27 changes: 26 additions & 1 deletion components/FlexibleHeader/src/MDCFlexibleHeaderView.m
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
#import "MDCMath.h"
#import "MDCLayoutMetrics.h"

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

#if TARGET_IPHONE_SIMULATOR
float UIAnimationDragCoefficient(void); // Private API for simulator animation speed
#endif
Expand Down Expand Up @@ -611,10 +618,12 @@ - (void)fhv_removeInsetsFromScrollView:(UIScrollView *)scrollView {
info.hasInjectedTopContentInset = NO;
scrollView.contentInset = insets;

#if !IS_VISIONOS
UIEdgeInsets scrollIndicatorInsets = scrollView.scrollIndicatorInsets;
scrollIndicatorInsets.top -= info.injectedTopScrollIndicatorInset;
info.injectedTopScrollIndicatorInset = 0;
scrollView.scrollIndicatorInsets = scrollIndicatorInsets;
#endif
info.injectedTopScrollIndicatorInset = 0;
}

- (CGFloat)fhv_existingContentInsetAdjustmentForScrollView:(UIScrollView *)scrollView {
Expand Down Expand Up @@ -680,7 +689,11 @@ - (CGFloat)fhv_enforceInsetsForScrollView:(UIScrollView *)scrollView {
scrollView.contentInset = insets;
}

#if IS_VISIONOS
BOOL statusBarIsHidden = YES;
#else
BOOL statusBarIsHidden = [UIApplication mdc_safeSharedApplication].statusBarHidden ? YES : NO;
#endif
if (_wasStatusBarHiddenIsValid && _wasStatusBarHidden != statusBarIsHidden &&
!_isChangingStatusBarVisibility && !self.inferTopSafeAreaInsetFromViewController) {
// Our status bar state has changed without our knowledge. UIKit will have already adjusted our
Expand Down Expand Up @@ -753,7 +766,11 @@ - (CGFloat)fhv_projectedHeaderBottomEdge {

- (CGFloat)fhv_accumulatorMax {
BOOL shouldCollapseToStatusBar = [self fhv_shouldCollapseToStatusBar];
#if IS_VISIONOS
CGFloat statusBarHeight = 0.0;
#else
CGFloat statusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
#endif
return (shouldCollapseToStatusBar
? MAX(0, self.minMaxHeight.minimumHeightWithTopSafeArea - statusBarHeight)
: self.minMaxHeight.minimumHeightWithTopSafeArea) -
Expand Down Expand Up @@ -822,8 +839,12 @@ - (void)fhv_recalculatePhase {
_scrollPhaseValue = topEdge + self.minMaxHeight.minimumHeightWithTopSafeArea;
CGFloat adjustedHeight = self.minMaxHeight.minimumHeightWithTopSafeArea;
if ([self fhv_shouldCollapseToStatusBar]) {
#if IS_VISIONOS
CGFloat statusBarHeight = 0.0;
#else
CGFloat statusBarHeight =
[UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
#endif
adjustedHeight -= statusBarHeight;
}
if (adjustedHeight > 0) {
Expand Down Expand Up @@ -988,7 +1009,11 @@ - (void)fhv_accumulatorDidChange {
self.hidden = isHidden;
}

#if IS_VISIONOS
UIEdgeInsets scrollIndicatorInsets = _trackingScrollView.horizontalScrollIndicatorInsets;
#else
UIEdgeInsets scrollIndicatorInsets = _trackingScrollView.scrollIndicatorInsets;
#endif
scrollIndicatorInsets.top -= _trackingInfo.injectedTopScrollIndicatorInset;

CGFloat existingContentInsetAdjustment =
Expand Down
39 changes: 39 additions & 0 deletions components/FlexibleHeader/src/MDCFlexibleHeaderViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@
#import "MDCLayoutMetrics.h"
#import <MDFTextAccessibility/MDFTextAccessibility.h>

#if defined(TARGET_OS_VISION) && TARGET_OS_VISION
// For code review, use the review queue listed in go/material-visionos-review.
#define IS_VISIONOS 1
#else
#define IS_VISIONOS 0
#endif

@interface UIView ()
- (UIEdgeInsets)safeAreaInsets; // For pre-iOS 11 SDK targets.
@end
Expand Down Expand Up @@ -136,8 +143,21 @@ - (instancetype)initWithCoder:(NSCoder *)aDecoder {
- (void)commonMDCFlexibleHeaderViewControllerInit {
_inferPreferredStatusBarStyle = YES;

#if IS_VISIONOS
UIWindow *keyWindow = nil;
for (UIScene *scene in UIApplication.sharedApplication.connectedScenes) {
if ([scene isKindOfClass:[UIWindowScene class]]) {
UIWindowScene *windowScene = (UIWindowScene *)scene;
keyWindow = windowScene.keyWindow;
break;
}
}
MDCFlexibleHeaderView *headerView =
[[MDCFlexibleHeaderView alloc] initWithFrame:keyWindow.bounds];
#else
MDCFlexibleHeaderView *headerView =
[[MDCFlexibleHeaderView alloc] initWithFrame:[UIScreen mainScreen].bounds];
#endif
headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
headerView.delegate = self;
_headerView = headerView;
Expand All @@ -152,6 +172,7 @@ - (void)loadView {
- (void)willMoveToParentViewController:(UIViewController *)parent {
[super willMoveToParentViewController:parent];

#if !IS_VISIONOS
BOOL shouldDisableAutomaticInsetting = YES;
// Prior to iOS 11 there was no way to know whether UIKit had injected insets into our
// UIScrollView, so we disable automatic insetting on these devices. iOS 11 provides
Expand All @@ -161,6 +182,7 @@ - (void)willMoveToParentViewController:(UIViewController *)parent {
if (shouldDisableAutomaticInsetting) {
parent.automaticallyAdjustsScrollViewInsets = NO;
}
#endif
}

- (void)didMoveToParentViewController:(UIViewController *)parent {
Expand Down Expand Up @@ -199,13 +221,18 @@ - (void)viewWillAppear:(BOOL)animated {
// Querying the top layout guide ensures that the flexible header receives layout event when
// the status bar visibility changes. This allows the flexible header to animate alongside any
// status bar visibility changes.
#if !IS_VISIONOS
[self.parentViewController topLayoutGuide];
#else
[self.parentViewController.view safeAreaLayoutGuide];
#endif
}

if (self.topLayoutGuideAdjustmentEnabled) {
[self updateTopLayoutGuide];

} else {
#if !IS_VISIONOS
// Legacy behavior.
for (NSLayoutConstraint *constraint in self.parentViewController.view.constraints) {
// Because topLayoutGuide is a readonly property on a viewController we must manipulate
Expand All @@ -215,6 +242,7 @@ - (void)viewWillAppear:(BOOL)animated {
self.topLayoutGuideConstraint = constraint;
}
}
#endif

// On moving to parentViewController, we calculate the height
self.flexibleHeaderViewControllerHeightOffset = [self headerViewControllerHeight];
Expand Down Expand Up @@ -372,6 +400,10 @@ - (void)fhv_extractTopLayoutGuideConstraint {

- (NSLayoutConstraint *)fhv_topLayoutGuideConstraintForViewController:
(UIViewController *)viewController {
#if IS_VISIONOS
// We could look at the view's safe area anchors if this is incorrect.
return nil;
#else
// Note: accessing topLayoutGuide has the side effect of setting up all of the view controller
// constraints. We need to access this property before we enter the for loop, otherwise
// view.constraints will be empty.
Expand All @@ -383,6 +415,7 @@ - (NSLayoutConstraint *)fhv_topLayoutGuideConstraintForViewController:
}
}
return foundConstraint;
#endif
}

- (void)setTopLayoutGuideConstraint:(NSLayoutConstraint *)topLayoutGuideConstraint {
Expand Down Expand Up @@ -537,7 +570,11 @@ - (void)updateTopLayoutGuide {
- (CGFloat)headerViewControllerHeight {
BOOL shiftEnabledForStatusBar =
_headerView.shiftBehavior == MDCFlexibleHeaderShiftBehaviorEnabledWithStatusBar;
#if IS_VISIONOS
CGFloat statusBarHeight = 0.0;
#else
CGFloat statusBarHeight = [UIApplication mdc_safeSharedApplication].statusBarFrame.size.height;
#endif
CGFloat height = MAX(_headerView.frame.origin.y + _headerView.frame.size.height,
shiftEnabledForStatusBar ? 0 : statusBarHeight);
return height;
Expand Down Expand Up @@ -676,7 +713,9 @@ - (void)fhv_inferTopSafeAreaSourceViewController {

- (void)flexibleHeaderViewNeedsStatusBarAppearanceUpdate:
(__unused MDCFlexibleHeaderView *)headerView {
#if !IS_VISIONOS
[self setNeedsStatusBarAppearanceUpdate];
#endif
}

- (void)flexibleHeaderViewFrameDidChange:(MDCFlexibleHeaderView *)headerView {
Expand Down
Loading

0 comments on commit 8f69468

Please sign in to comment.