Skip to content
This repository has been archived by the owner on Apr 11, 2024. It is now read-only.

Commit

Permalink
Allow not to use UIImageAsset on iOS 13 (#88)
Browse files Browse the repository at this point in the history
* Allow not to use UIImageAsset on iOS13

* Use imageWithConfiguration: on iOS 13+

* Add configuration class
  • Loading branch information
levinli303 committed Jul 24, 2020
1 parent f94228e commit 5883735
Show file tree
Hide file tree
Showing 19 changed files with 290 additions and 134 deletions.
24 changes: 24 additions & 0 deletions FluentDarkModeKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,14 @@
8CDA62A52366DAA9004895B5 /* DMDynamicColor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */; settings = {ATTRIBUTES = (Public, ); }; };
8CE066CF239E5582002CE16D /* UIColor+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */; };
8CE066D0239E5586002CE16D /* UIImage+DarkModeKit.m in Sources */ = {isa = PBXBuildFile; fileRef = 8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */; };
EA1BAF6724C581C5006E755F /* UIView+DarkModeKitSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */; };
EA1BAF6824C581C5006E755F /* UIView+DarkModeKitSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */; };
EA1BAF6F24C58447006E755F /* UIImage+DarkModeKitSwizzling.h in Headers */ = {isa = PBXBuildFile; fileRef = EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */; };
EA1BAF7024C58447006E755F /* UIImage+DarkModeKitSwizzling.m in Sources */ = {isa = PBXBuildFile; fileRef = EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */; };
EA2EA50024A1CBF2001AE312 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA2EA4FE24A1CAD5001AE312 /* SceneDelegate.swift */; };
EA7316F1248F5055009AE037 /* UILabelVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7316EF248F5050009AE037 /* UILabelVC.swift */; };
EAC41E2F24CADD6E0033C9AC /* DMEnvironmentConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
EAC41E3024CADD6E0033C9AC /* DMEnvironmentConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */; };
EAE6065624A9DA1B001304D1 /* UIImageViewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAE6065324A9D9E0001304D1 /* UIImageViewVC.swift */; };
/* End PBXBuildFile section */

Expand Down Expand Up @@ -148,8 +154,14 @@
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DMDynamicImage.m; sourceTree = "<group>"; };
8CDA628A2366DAA9004895B5 /* DarkModeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DarkModeManager.swift; sourceTree = "<group>"; };
8CDA628B2366DAA9004895B5 /* DMDynamicColor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DMDynamicColor.h; sourceTree = "<group>"; };
EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+DarkModeKitSwizzling.h"; sourceTree = "<group>"; };
EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIView+DarkModeKitSwizzling.m"; sourceTree = "<group>"; };
EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIImage+DarkModeKitSwizzling.h"; sourceTree = "<group>"; };
EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIImage+DarkModeKitSwizzling.m"; sourceTree = "<group>"; };
EA2EA4FE24A1CAD5001AE312 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
EA7316EF248F5050009AE037 /* UILabelVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UILabelVC.swift; sourceTree = "<group>"; };
EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DMEnvironmentConfiguration.h; sourceTree = "<group>"; };
EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DMEnvironmentConfiguration.m; sourceTree = "<group>"; };
EAE6065324A9D9E0001304D1 /* UIImageViewVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIImageViewVC.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

Expand Down Expand Up @@ -214,15 +226,21 @@
8CDA62732366DAA9004895B5 /* DMDynamicColor.m */,
8CDA62762366DAA9004895B5 /* DMDynamicImage.h */,
8CDA62892366DAA9004895B5 /* DMDynamicImage.m */,
EAC41E2D24CADD6E0033C9AC /* DMEnvironmentConfiguration.h */,
EAC41E2E24CADD6E0033C9AC /* DMEnvironmentConfiguration.m */,
8CDA62712366DAA9004895B5 /* DMTraitCollection.h */,
8CDA62722366DAA9004895B5 /* DMTraitCollection.m */,
8CC8D86F2398E7520043276A /* DMNamespace.h */,
8CC8D86B2398E4EC0043276A /* UIColor+DarkModeKit.h */,
8CC8D86C2398E4EC0043276A /* UIColor+DarkModeKit.m */,
8CC8D8712398E7A30043276A /* UIImage+DarkModeKit.h */,
8CC8D8722398E7A30043276A /* UIImage+DarkModeKit.m */,
EA1BAF6D24C58447006E755F /* UIImage+DarkModeKitSwizzling.h */,
EA1BAF6E24C58447006E755F /* UIImage+DarkModeKitSwizzling.m */,
8CB63E3F238551F3008ABCE2 /* UIView+DarkModeKit.h */,
8CB63E40238551F3008ABCE2 /* UIView+DarkModeKit.m */,
EA1BAF6524C581C5006E755F /* UIView+DarkModeKitSwizzling.h */,
EA1BAF6624C581C5006E755F /* UIView+DarkModeKitSwizzling.m */,
);
path = DarkModeCore;
sourceTree = "<group>";
Expand Down Expand Up @@ -337,7 +355,10 @@
buildActionMask = 2147483647;
files = (
8CC8D86D2398E4EC0043276A /* UIColor+DarkModeKit.h in Headers */,
EA1BAF6724C581C5006E755F /* UIView+DarkModeKitSwizzling.h in Headers */,
EA1BAF6F24C58447006E755F /* UIImage+DarkModeKitSwizzling.h in Headers */,
8CC8D8702398E7520043276A /* DMNamespace.h in Headers */,
EAC41E2F24CADD6E0033C9AC /* DMEnvironmentConfiguration.h in Headers */,
8CDA628D2366DAA9004895B5 /* DMTraitCollection.h in Headers */,
8CDA628C2366DAA9004895B5 /* FluentDarkModeKit.h in Headers */,
8CB63E41238551F3008ABCE2 /* UIView+DarkModeKit.h in Headers */,
Expand Down Expand Up @@ -531,9 +552,11 @@
buildActionMask = 2147483647;
files = (
8CDA62972366DAA9004895B5 /* UIScrollView+DarkModeKit.swift in Sources */,
EAC41E3024CADD6E0033C9AC /* DMEnvironmentConfiguration.m in Sources */,
8CB63E42238551F3008ABCE2 /* UIView+DarkModeKit.m in Sources */,
8CDA62A12366DAA9004895B5 /* UITextField+DarkModeKit.swift in Sources */,
8CDA62952366DAA9004895B5 /* UIWindow+DarkModeKit.swift in Sources */,
EA1BAF6824C581C5006E755F /* UIView+DarkModeKitSwizzling.m in Sources */,
8CDA629E2366DAA9004895B5 /* UIViewController+DarkModeKit.swift in Sources */,
8CDA62992366DAA9004895B5 /* UIImageView+DarkModeKit.swift in Sources */,
8CDA62962366DAA9004895B5 /* UIProgressView+DarkModeKit.swift in Sources */,
Expand All @@ -551,6 +574,7 @@
8CDA62922366DAA9004895B5 /* UIToolbar+DarkModeKit.swift in Sources */,
8CDA629A2366DAA9004895B5 /* UIPageControl+DarkModeKit.swift in Sources */,
8CDA62932366DAA9004895B5 /* UIButton+DarkModeKit.swift in Sources */,
EA1BAF7024C58447006E755F /* UIImage+DarkModeKitSwizzling.m in Sources */,
8CDA629B2366DAA9004895B5 /* UITableView+DarkModeKit.swift in Sources */,
8CDA629F2366DAA9004895B5 /* UILabel+DarkModeKit.swift in Sources */,
);
Expand Down
10 changes: 8 additions & 2 deletions Sources/DarkModeCore/DMDynamicImage.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,8 @@ - (instancetype)initWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)da
- (UIImage *)resolvedImage {
if (DMTraitCollection.overrideTraitCollection.userInterfaceStyle == DMUserInterfaceStyleDark) {
return self.darkImage;
} else {
return self.lightImage;
}
return self.lightImage;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel {
Expand Down Expand Up @@ -88,6 +87,13 @@ - (UIImage *)imageWithHorizontallyFlippedOrientation {
darkImage:[self.darkImage imageWithHorizontallyFlippedOrientation]];
}

- (UIImage *)imageWithConfiguration:(UIImageConfiguration *)configuration API_AVAILABLE(ios(13.0)) {
if (configuration.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark) {
return [_darkImage imageWithConfiguration:configuration];
}
return [_lightImage imageWithConfiguration:configuration];
}

- (id)copy {
return [self copyWithZone:nil];
}
Expand Down
18 changes: 18 additions & 0 deletions Sources/DarkModeCore/DMEnvironmentConfiguration.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface DMEnvironmentConfiguration : NSObject

@property (nonatomic) BOOL useImageAsset; // Defaults to NO

- (instancetype)init;

@end

NS_ASSUME_NONNULL_END
18 changes: 18 additions & 0 deletions Sources/DarkModeCore/DMEnvironmentConfiguration.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//

#import "DMEnvironmentConfiguration.h"

@implementation DMEnvironmentConfiguration

- (instancetype)init {
self = [super init];
if (self) {
_useImageAsset = NO;
}
return self;
}

@end
8 changes: 4 additions & 4 deletions Sources/DarkModeCore/DMTraitCollection.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

#import <UIKit/UIKit.h>

@class UITraitCollection;
@class UITraitCollection, DMEnvironmentConfiguration;

NS_ASSUME_NONNULL_BEGIN

Expand Down Expand Up @@ -35,9 +35,9 @@ typedef NS_ENUM(NSInteger, DMUserInterfaceStyle) {
+ (void)registerWithViewController:(UIViewController *)viewController syncImmediately:(BOOL)syncImmediately animated:(BOOL)animated;
+ (void)unregister;

// MARK: - Swizzling
// TODO: move swizzling to private header
+ (void)swizzleUIScreenTraitCollectionDidChange API_AVAILABLE(ios(13.0));
// MARK: - Setup
// TODO: Move to private header
+ (void)setupEnvironmentWithConfiguration:(DMEnvironmentConfiguration *)configuration;

@end

Expand Down
24 changes: 22 additions & 2 deletions Sources/DarkModeCore/DMTraitCollection.m
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
// Licensed under the MIT License.
//

#import "DMEnvironmentConfiguration.h"
#import "DMTraitCollection.h"
#import "UIView+DarkModeKit.h"
#import "UIView+DarkModeKitSwizzling.h"
#import "UIImage+DarkModeKitSwizzling.h"

@import ObjectiveC;

Expand Down Expand Up @@ -243,7 +245,7 @@ + (void)unregister {
}

// MARK: - Swizzling
+ (void)swizzleUIScreenTraitCollectionDidChange {
+ (void)swizzleUIScreenTraitCollectionDidChange API_AVAILABLE(ios(13.0)) {
static dispatch_once_t onceToken;
__weak typeof(self) weakSelf = self;
dispatch_once(&onceToken, ^{
Expand All @@ -258,6 +260,24 @@ + (void)swizzleUIScreenTraitCollectionDidChange {
});
}

+ (void)setupEnvironmentWithConfiguration:(DMEnvironmentConfiguration *)configuration {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
if (@available(iOS 13.0, *)) {
[DMTraitCollection swizzleUIScreenTraitCollectionDidChange];
[UIView swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange];
[UIViewController swizzleTraitCollectionDidChangeToDMTraitCollectionDidChange];
if (!configuration.useImageAsset)
[UIImage dm_swizzleIsEqual];
}
else {
[UIView dm_swizzleSetTintColor];
[UIView dm_swizzleSetBackgroundColor];
[UIImage dm_swizzleIsEqual];
}
});
}

@end

@interface UIScreen (DMTraitEnvironment) <DMTraitEnvironment>
Expand Down
1 change: 1 addition & 0 deletions Sources/DarkModeCore/FluentDarkModeKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#import <FluentDarkModeKit/DMDynamicColor.h>
#import <FluentDarkModeKit/DMDynamicImage.h>
#import <FluentDarkModeKit/DMEnvironmentConfiguration.h>
#import <FluentDarkModeKit/DMTraitCollection.h>
#import <FluentDarkModeKit/UIColor+DarkModeKit.h>
#import <FluentDarkModeKit/UIImage+DarkModeKit.h>
Expand Down
2 changes: 0 additions & 2 deletions Sources/DarkModeCore/UIImage+DarkModeKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ NS_ASSUME_NONNULL_BEGIN

@interface UIImage (DarkModeKit)

+ (void)dm_swizzleIsEqual;

+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage
NS_SWIFT_UNAVAILABLE("Use init(_:light:dark:) instead.");

Expand Down
54 changes: 16 additions & 38 deletions Sources/DarkModeCore/UIImage+DarkModeKit.m
Original file line number Diff line number Diff line change
Expand Up @@ -4,53 +4,31 @@
//

#import "UIImage+DarkModeKit.h"
#import "UIImage+DarkModeKitSwizzling.h"
#import "DMDynamicImage.h"
#import "DMTraitCollection.h"

@import ObjectiveC;

@implementation UIImage (DarkModeKit)

+ (void)dm_swizzleIsEqual {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(isEqual:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIImage isEqual:]");

IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^BOOL(UIImage *self, UIImage *other) {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return ((BOOL(*)(UIImage *, SEL, UIImage *))imp)(realSelf, selector, realOther);
}), method_getTypeEncoding(method));
});
}

+ (UIImage *)dm_imageWithLightImage:(UIImage *)lightImage darkImage:(UIImage *)darkImage {
if (@available(iOS 13, *)) {
UIImageAsset *imageAsset = [[UIImageAsset alloc] init];

// Always specify a displayScale otherwise a default of 1.0 is assigned
[imageAsset registerImage:lightImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight],
[UITraitCollection traitCollectionWithDisplayScale:lightImage.scale]
]]];
[imageAsset registerImage:darkImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
[UITraitCollection traitCollectionWithDisplayScale:darkImage.scale]
]]];

return [imageAsset imageWithTraitCollection:DMTraitCollection.overrideTraitCollection.uiTraitCollection];
if ([UIImage useUIImageAsset]) {
UIImageAsset *imageAsset = [[UIImageAsset alloc] init];

// Always specify a displayScale otherwise a default of 1.0 is assigned
[imageAsset registerImage:lightImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleLight],
[UITraitCollection traitCollectionWithDisplayScale:lightImage.scale]
]]];
[imageAsset registerImage:darkImage withTraitCollection:[UITraitCollection traitCollectionWithTraitsFromCollections:@[
[UITraitCollection traitCollectionWithUserInterfaceStyle:UIUserInterfaceStyleDark],
[UITraitCollection traitCollectionWithDisplayScale:darkImage.scale]
]]];

return [imageAsset imageWithTraitCollection:DMTraitCollection.overrideTraitCollection.uiTraitCollection];
}
}

return (UIImage *)[[DMDynamicImageProxy alloc] initWithLightImage:lightImage darkImage:darkImage];
Expand Down
18 changes: 18 additions & 0 deletions Sources/DarkModeCore/UIImage+DarkModeKitSwizzling.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//

#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

@interface UIImage (DarkModeKitSwizzling)

@property (class, readonly) BOOL useUIImageAsset;

+ (void)dm_swizzleIsEqual;

@end

NS_ASSUME_NONNULL_END
46 changes: 46 additions & 0 deletions Sources/DarkModeCore/UIImage+DarkModeKitSwizzling.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//

#import "UIImage+DarkModeKitSwizzling.h"
#import "DMDynamicImage.h"

@import ObjectiveC;

static BOOL _useUIImageAsset = YES;

@implementation UIImage (DarkModeKitSwizzling)

+ (BOOL)useUIImageAsset {
return _useUIImageAsset;
}

+ (void)dm_swizzleIsEqual {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL selector = @selector(isEqual:);
Method method = class_getInstanceMethod(self, selector);
if (!method)
NSAssert(NO, @"Method not found for [UIImage isEqual:]");

IMP imp = method_getImplementation(method);
class_replaceMethod(self, selector, imp_implementationWithBlock(^BOOL(UIImage *self, UIImage *other) {
/// On iOS 13, UIImage `isEqual:` somehow changes internally and doesn't work for `NSProxy`,
/// here we forward the message to internal images manually
UIImage *realSelf = self;
UIImage *realOther = other;
if (object_getClass(self) == DMDynamicImageProxy.class) {
realSelf = ((DMDynamicImageProxy *)self).resolvedImage;
}
if (object_getClass(other) == DMDynamicImageProxy.class) {
realOther = ((DMDynamicImageProxy *)other).resolvedImage;
}
return ((BOOL(*)(UIImage *, SEL, UIImage *))imp)(realSelf, selector, realOther);
}), method_getTypeEncoding(method));

_useUIImageAsset = NO;
});
}

@end
3 changes: 0 additions & 3 deletions Sources/DarkModeCore/UIView+DarkModeKit.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ NS_ASSUME_NONNULL_BEGIN

@interface UIView (DarkModeKit) <DMTraitEnvironment>

+ (void)dm_swizzleSetBackgroundColor;
+ (void)dm_swizzleSetTintColor;

- (void)dm_updateDynamicColors API_DEPRECATED("dm_updateDynamicColors is deprecated and will not be called on iOS 13.0, use dmTraitCollectionDidChange: instead", ios(11.0, 13.0));;
- (void)dm_updateDynamicImages API_DEPRECATED("dm_updateDynamicImages is deprecated and will not be called on iOS 13.0, use dmTraitCollectionDidChange: instead", ios(11.0, 13.0));;

Expand Down
Loading

0 comments on commit 5883735

Please sign in to comment.