From b831dd788adbe662f33d9f6a0a497bbd52e61533 Mon Sep 17 00:00:00 2001 From: fanxinghua Date: Fri, 3 Jul 2026 11:04:51 +0800 Subject: [PATCH 1/5] Fix notch corner mask using stale view bounds applyCornerStyling read notchView.bounds before the frame was assigned, so the mask was drawn against the previous (or zero) size. Pass the computed adjustedFrame explicitly and draw the mask in the view's own zero-origin coordinate space to avoid offset on dynamic-island models. Co-Authored-By: Claude Opus 4 --- TopNotch/TopNotchManager.swift | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/TopNotch/TopNotchManager.swift b/TopNotch/TopNotchManager.swift index 8a7906c..24b9c6b 100644 --- a/TopNotch/TopNotchManager.swift +++ b/TopNotch/TopNotchManager.swift @@ -220,7 +220,7 @@ public final class TopNotchManager { let newHeight = rawRect.height * override.heightFactor adjustedFrame = CGRect(x: newX, y: rawRect.origin.y, width: newWidth, height: newHeight) print("[TopNotchManager] Applied individual override for \(modelId): \(adjustedFrame)") - applyCornerStyling(with: override.radius, roundBottomOnly: true) + applyCornerStyling(with: override.radius, bounds: adjustedFrame, roundBottomOnly: true) } // Otherwise, check for series overrides. else if let seriesOverride = modelSeriesOverrides.first(where: { modelId.hasPrefix($0.key) }) { @@ -230,18 +230,18 @@ public final class TopNotchManager { let newHeight = rawRect.height * override.heightFactor adjustedFrame = CGRect(x: newX, y: rawRect.origin.y, width: newWidth, height: newHeight) print("[TopNotchManager] Applied series override for \(modelId) (prefix \(seriesOverride.key)): \(adjustedFrame)") - applyCornerStyling(with: override.radius, roundBottomOnly: true) + applyCornerStyling(with: override.radius, bounds: adjustedFrame, roundBottomOnly: true) } // Otherwise, use default styling. else { adjustedFrame = rawRect if rawRect.origin.y > 0 { let capsuleRadius = rawRect.height / 2 - applyCornerStyling(with: capsuleRadius) + applyCornerStyling(with: capsuleRadius, bounds: adjustedFrame) print("[TopNotchManager] Dynamic island default styling (radius \(capsuleRadius))") } else { // Use a slightly increased radius for original notches to prevent clipping. - applyCornerStyling(with: 21, roundBottomOnly: true) + applyCornerStyling(with: 21, bounds: adjustedFrame, roundBottomOnly: true) print("[TopNotchManager] Original notch default styling (radius 21)") } } @@ -254,23 +254,25 @@ public final class TopNotchManager { /// /// - Parameters: /// - radius: The corner radius to apply. + /// - bounds: The size to draw the mask against, in the view's own coordinate space. /// - roundBottomOnly: If `true`, only the bottom corners will be rounded. - private func applyCornerStyling(with radius: CGFloat, roundBottomOnly: Bool = false) { + private func applyCornerStyling(with radius: CGFloat, bounds: CGRect, roundBottomOnly: Bool = false) { guard let view = notchView else { return } // Disable default clipping. view.clipsToBounds = false - + + let rect = CGRect(origin: .zero, size: bounds.size) let path: UIBezierPath if roundBottomOnly { - path = UIBezierPath(roundedRect: view.bounds, + path = UIBezierPath(roundedRect: rect, byRoundingCorners: [.bottomLeft, .bottomRight], cornerRadii: CGSize(width: radius, height: radius)) } else { - path = UIBezierPath(roundedRect: view.bounds, cornerRadius: radius) + path = UIBezierPath(roundedRect: rect, cornerRadius: radius) } - + let maskLayer = CAShapeLayer() - maskLayer.frame = view.bounds + maskLayer.frame = rect maskLayer.path = path.cgPath view.layer.mask = maskLayer } From c7b54898272de57b02eac0f35810c675a1b5e792 Mon Sep 17 00:00:00 2001 From: fanxinghua Date: Fri, 3 Jul 2026 11:19:20 +0800 Subject: [PATCH 2/5] Honor shouldAnimate config in notch transitions Route all fade transitions through an applyChanges helper that applies changes instantly when shouldAnimate is false. Co-Authored-By: Claude Opus 4 --- TopNotch/TopNotchManager.swift | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/TopNotch/TopNotchManager.swift b/TopNotch/TopNotchManager.swift index 24b9c6b..bebfff5 100644 --- a/TopNotch/TopNotchManager.swift +++ b/TopNotch/TopNotchManager.swift @@ -122,8 +122,8 @@ public final class TopNotchManager { notchView?.alpha = 0 updateNotchFrame() - // Animate fade-in. - UIView.animate(withDuration: config.animationDuration) { + // Fade in (or apply instantly when animation is disabled). + applyChanges { self.notchView?.alpha = 1.0 } print("[TopNotchManager] Notch view fading in") @@ -152,7 +152,7 @@ public final class TopNotchManager { public func hide() { print("[TopNotchManager] Hiding notch view") NotificationCenter.default.removeObserver(self) - UIView.animate(withDuration: config.animationDuration, animations: { + applyChanges({ self.notchView?.alpha = 0 }) { _ in print("[TopNotchManager] Notch view removed from superview") @@ -162,7 +162,22 @@ public final class TopNotchManager { } // MARK: Private Helpers - + + /// Runs `animations` with a fade, honoring `config.shouldAnimate`. + /// When animation is disabled the changes are applied instantly and + /// `completion` still fires so teardown logic runs identically. + private func applyChanges(_ animations: @escaping () -> Void, + completion: ((Bool) -> Void)? = nil) { + guard config.shouldAnimate else { + animations() + completion?(true) + return + } + UIView.animate(withDuration: config.animationDuration, + animations: animations, + completion: completion) + } + /// Creates a default notch view with a red tint. /// /// - Returns: A default `UIView` instance to be used as the notch view. @@ -283,7 +298,7 @@ public final class TopNotchManager { @objc private func sceneWillDeactivateNotification(_ notification: Notification) { if config.shouldHideForTaskSwitcher && isNotchVisible { print("[TopNotchManager] Hiding notch view for task switcher (willDeactivate)") - UIView.animate(withDuration: config.animationDuration) { + applyChanges { self.notchView?.alpha = 0 } } @@ -293,7 +308,7 @@ public final class TopNotchManager { @objc private func sceneDidActivateNotification(_ notification: Notification) { if config.shouldHideForTaskSwitcher && isNotchVisible { print("[TopNotchManager] Showing notch view after task switcher (didActivate)") - UIView.animate(withDuration: config.animationDuration) { + applyChanges { self.notchView?.alpha = 1.0 } } From bc45a49e6298d608f658da41c5847639d9f7094a Mon Sep 17 00:00:00 2001 From: fanxinghua Date: Fri, 3 Jul 2026 18:02:48 +0800 Subject: [PATCH 3/5] Support Swift Package --- .gitignore | 8 + Example/Sources/ContentView.swift | 42 ++ Example/demo.xcodeproj/project.pbxproj | 378 ++++++++++++ .../contents.xcworkspacedata | 0 Package.swift | 15 + README.md | 1 - .../Resources => Resources}/banner.png | Bin .../Resources => Resources}/demo.mp4 | Bin .../Resources => Resources}/poster.jpg | Bin .../TopNotchConfiguration.swift | 0 {TopNotch => Sources}/TopNotchManager.swift | 0 {TopNotch => Sources}/TopNotchModifier.swift | 0 {TopNotch => Sources}/UIDevice+Model.swift | 0 TopNotch.xcodeproj/project.pbxproj | 547 ------------------ .../xcschemes/xcschememanagement.plist | 19 - TopNotch/TopNotch.docc/TopNotch.md | 42 -- TopNotch/TopNotch.h | 18 - TopNotchDemo/AppDelegate.swift | 19 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 35 -- TopNotchDemo/Assets.xcassets/Contents.json | 6 - .../FontCollectionViewController.swift | 70 --- TopNotchDemo/Info.plist | 23 - TopNotchDemo/ModalSheetViewController.swift | 23 - TopNotchDemo/SceneDelegate.swift | 28 - 25 files changed, 443 insertions(+), 842 deletions(-) create mode 100644 .gitignore create mode 100644 Example/Sources/ContentView.swift create mode 100644 Example/demo.xcodeproj/project.pbxproj rename {TopNotch.xcodeproj => Example/demo.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (100%) create mode 100644 Package.swift delete mode 120000 README.md rename {TopNotch/TopNotch.docc/Resources => Resources}/banner.png (100%) rename {TopNotch/TopNotch.docc/Resources => Resources}/demo.mp4 (100%) rename {TopNotch/TopNotch.docc/Resources => Resources}/poster.jpg (100%) rename {TopNotch => Sources}/TopNotchConfiguration.swift (100%) rename {TopNotch => Sources}/TopNotchManager.swift (100%) rename {TopNotch => Sources}/TopNotchModifier.swift (100%) rename {TopNotch => Sources}/UIDevice+Model.swift (100%) delete mode 100644 TopNotch.xcodeproj/project.pbxproj delete mode 100644 TopNotch.xcodeproj/xcuserdata/shg.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 TopNotch/TopNotch.docc/TopNotch.md delete mode 100644 TopNotch/TopNotch.h delete mode 100644 TopNotchDemo/AppDelegate.swift delete mode 100644 TopNotchDemo/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 TopNotchDemo/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 TopNotchDemo/Assets.xcassets/Contents.json delete mode 100644 TopNotchDemo/FontCollectionViewController.swift delete mode 100644 TopNotchDemo/Info.plist delete mode 100644 TopNotchDemo/ModalSheetViewController.swift delete mode 100644 TopNotchDemo/SceneDelegate.swift diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..46735f3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +.DS_Store +.build/ +DerivedData/ +*.xcuserstate +xcuserdata/ +.swiftpm/ +Package.resolved +.claude diff --git a/Example/Sources/ContentView.swift b/Example/Sources/ContentView.swift new file mode 100644 index 0000000..d676702 --- /dev/null +++ b/Example/Sources/ContentView.swift @@ -0,0 +1,42 @@ +import SwiftUI +import Playgrounds +import TopNotch + +@main struct MyApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} + +struct ContentView: View { + @Environment(\.scenePhase) private var scenePhase + var body: some View { + Text("Hello world!") + .padding() + .onChange(of: scenePhase) { + if scenePhase == .active { + showTopNotch() + } + } + } + + func showTopNotch() { + // Create a custom view (or use your own) to display behind the notch. + let notchLabel = UILabel() + notchLabel.text = "TopNotch" + notchLabel.textAlignment = .center + notchLabel.textColor = .white + notchLabel.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.7) + + // Show the notch view. + TopNotchManager.shared.show(customView: notchLabel, with: .init(animationDuration: 0.3, + shouldAnimate: true, + shouldHideForTaskSwitcher: false)) + } +} + +#Preview { + ContentView() +} diff --git a/Example/demo.xcodeproj/project.pbxproj b/Example/demo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..ae844bf --- /dev/null +++ b/Example/demo.xcodeproj/project.pbxproj @@ -0,0 +1,378 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 90; + objects = { + +/* Begin PBXBuildFile section */ + 8DDFC4352FF7B9B00012A570 /* TopNotch in Frameworks */ = {isa = PBXBuildFile; productRef = 8DDFC4342FF7B9B00012A570 /* TopNotch */; }; + 8DDFC43C2FF7BFB60012A570 /* TopNotch in Frameworks */ = {isa = PBXBuildFile; productRef = 8DDFC43B2FF7BFB60012A570 /* TopNotch */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 000000000000000000000120 /* demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = demo.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 000000000000000000000010 /* Sources */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = Sources; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 000000000000000130000000 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + files = ( + 8DDFC4352FF7B9B00012A570 /* TopNotch in Frameworks */, + 8DDFC43C2FF7BFB60012A570 /* TopNotch in Frameworks */, + ); + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 000000000000000000000001 = { + isa = PBXGroup; + children = ( + 000000000000000000000010 /* Sources */, + 000000000000000000000020 /* Products */, + ); + sourceTree = ""; + }; + 000000000000000000000020 /* Products */ = { + isa = PBXGroup; + children = ( + 000000000000000000000120 /* demo.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 000000000000000100000000 /* demo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 000000000000000110000000 /* Build configuration list for PBXNativeTarget "demo" */; + buildPhases = ( + 000000000000000120000000 /* Sources */, + 000000000000000130000000 /* Frameworks */, + 000000000000000140000000 /* Resources */, + ); + buildRules = ( + ); + fileSystemSynchronizedGroups = ( + 000000000000000000000010 /* Sources */, + ); + name = demo; + packageProductDependencies = ( + 8DDFC4342FF7B9B00012A570 /* TopNotch */, + 8DDFC43B2FF7BFB60012A570 /* TopNotch */, + ); + productName = MyApp; + productReference = 000000000000000000000120 /* demo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 000000000000000000000000 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 2630; + LastUpgradeCheck = 2700; + TargetAttributes = { + 000000000000000100000000 = { + CreatedOnToolsVersion = 26.3; + }; + }; + }; + buildConfigurationList = 000000000000000010000000 /* Build configuration list for PBXProject "demo" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 000000000000000000000001; + minimizedProjectReferenceProxies = 1; + packageReferences = ( + 8DDFC43A2FF7BFB60012A570 /* XCLocalSwiftPackageReference "../../TopNotch" */, + ); + preferredProjectObjectVersion = 90; + productRefGroup = 000000000000000000000020 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 000000000000000100000000 /* demo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 000000000000000140000000 /* Resources */ = { + isa = PBXResourcesBuildPhase; + files = ( + ); + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 000000000000000120000000 /* Sources */ = { + isa = PBXSourcesBuildPhase; + files = ( + ); + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 000000000000000011000000 /* Debug configuration for PBXProject "demo" */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLETVOS_DEPLOYMENT_TARGET = 27.0; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + DRIVERKIT_DEPLOYMENT_TARGET = 27.0; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 27.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 27.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PROJECT_UNIQUE_VALUE = FHI928ZR; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + WATCHOS_DEPLOYMENT_TARGET = 27.0; + XROS_DEPLOYMENT_TARGET = 27.0; + }; + name = Debug; + }; + 000000000000000012000000 /* Release configuration for PBXProject "demo" */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + APPLETVOS_DEPLOYMENT_TARGET = 27.0; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DRIVERKIT_DEPLOYMENT_TARGET = 27.0; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 27.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 27.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PROJECT_UNIQUE_VALUE = FHI928ZR; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_COMPILATION_MODE = wholemodule; + WATCHOS_DEPLOYMENT_TARGET = 27.0; + XROS_DEPLOYMENT_TARGET = 27.0; + }; + name = Release; + }; + 000000000000000111000000 /* Debug configuration for PBXNativeTarget "demo" */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "devplaceholder.$(PROJECT_UNIQUE_VALUE:identifier).$(PRODUCT_NAME:identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + SDKROOT = auto; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,7"; + }; + name = Debug; + }; + 000000000000000112000000 /* Release configuration for PBXNativeTarget "demo" */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + ENABLE_APP_SANDBOX = YES; + ENABLE_PREVIEWS = YES; + ENABLE_USER_SELECTED_FILES = readonly; + GENERATE_INFOPLIST_FILE = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphoneos*]" = YES; + "INFOPLIST_KEY_UILaunchScreen_Generation[sdk=iphonesimulator*]" = YES; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphoneos*]" = UIStatusBarStyleDefault; + "INFOPLIST_KEY_UIStatusBarStyle[sdk=iphonesimulator*]" = UIStatusBarStyleDefault; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks"; + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks"; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "devplaceholder.$(PROJECT_UNIQUE_VALUE:identifier).$(PRODUCT_NAME:identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + SDKROOT = auto; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator"; + SWIFT_APPROACHABLE_CONCURRENCY = YES; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2,7"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 000000000000000010000000 /* Build configuration list for PBXProject "demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 000000000000000011000000 /* Debug configuration for PBXProject "demo" */, + 000000000000000012000000 /* Release configuration for PBXProject "demo" */, + ); + defaultConfigurationName = Release; + }; + 000000000000000110000000 /* Build configuration list for PBXNativeTarget "demo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 000000000000000111000000 /* Debug configuration for PBXNativeTarget "demo" */, + 000000000000000112000000 /* Release configuration for PBXNativeTarget "demo" */, + ); + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + 8DDFC43A2FF7BFB60012A570 /* XCLocalSwiftPackageReference "../../TopNotch" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = ../../TopNotch; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 8DDFC4342FF7B9B00012A570 /* TopNotch */ = { + isa = XCSwiftPackageProductDependency; + productName = TopNotch; + }; + 8DDFC43B2FF7BFB60012A570 /* TopNotch */ = { + isa = XCSwiftPackageProductDependency; + productName = TopNotch; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = 000000000000000000000000 /* Project object */; +} diff --git a/TopNotch.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from TopNotch.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to Example/demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..3bb2dc7 --- /dev/null +++ b/Package.swift @@ -0,0 +1,15 @@ +// swift-tools-version:5.9 +import PackageDescription + +let package = Package( + name: "TopNotch", + platforms: [ + .iOS(.v13), + ], + products: [ + .library(name: "TopNotch", targets: ["TopNotch"]), + ], + targets: [ + .target(name: "TopNotch"), + ] +) diff --git a/README.md b/README.md deleted file mode 120000 index 2ef36d7..0000000 --- a/README.md +++ /dev/null @@ -1 +0,0 @@ -./TopNotch/TopNotch.docc/TopNotch.md \ No newline at end of file diff --git a/TopNotch/TopNotch.docc/Resources/banner.png b/Resources/banner.png similarity index 100% rename from TopNotch/TopNotch.docc/Resources/banner.png rename to Resources/banner.png diff --git a/TopNotch/TopNotch.docc/Resources/demo.mp4 b/Resources/demo.mp4 similarity index 100% rename from TopNotch/TopNotch.docc/Resources/demo.mp4 rename to Resources/demo.mp4 diff --git a/TopNotch/TopNotch.docc/Resources/poster.jpg b/Resources/poster.jpg similarity index 100% rename from TopNotch/TopNotch.docc/Resources/poster.jpg rename to Resources/poster.jpg diff --git a/TopNotch/TopNotchConfiguration.swift b/Sources/TopNotchConfiguration.swift similarity index 100% rename from TopNotch/TopNotchConfiguration.swift rename to Sources/TopNotchConfiguration.swift diff --git a/TopNotch/TopNotchManager.swift b/Sources/TopNotchManager.swift similarity index 100% rename from TopNotch/TopNotchManager.swift rename to Sources/TopNotchManager.swift diff --git a/TopNotch/TopNotchModifier.swift b/Sources/TopNotchModifier.swift similarity index 100% rename from TopNotch/TopNotchModifier.swift rename to Sources/TopNotchModifier.swift diff --git a/TopNotch/UIDevice+Model.swift b/Sources/UIDevice+Model.swift similarity index 100% rename from TopNotch/UIDevice+Model.swift rename to Sources/UIDevice+Model.swift diff --git a/TopNotch.xcodeproj/project.pbxproj b/TopNotch.xcodeproj/project.pbxproj deleted file mode 100644 index 669f8ba..0000000 --- a/TopNotch.xcodeproj/project.pbxproj +++ /dev/null @@ -1,547 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - EAB4C7DE2D5AAA26000CE23F /* TopNotch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EAB4C7AF2D5AA7EB000CE23F /* TopNotch.framework */; }; - EAB4C7DF2D5AAA26000CE23F /* TopNotch.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = EAB4C7AF2D5AA7EB000CE23F /* TopNotch.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - EAB4C7E02D5AAA26000CE23F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = EAB4C7A62D5AA7EB000CE23F /* Project object */; - proxyType = 1; - remoteGlobalIDString = EAB4C7AE2D5AA7EB000CE23F; - remoteInfo = TopNotch; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - EAB4C7E22D5AAA26000CE23F /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - EAB4C7DF2D5AAA26000CE23F /* TopNotch.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - EAB4C7AF2D5AA7EB000CE23F /* TopNotch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TopNotch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - EAB4C7C82D5AA990000CE23F /* TopNotchDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TopNotchDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - EAB4C7B62D5AA7EB000CE23F /* Exceptions for "TopNotch" folder in "TopNotch" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - publicHeaders = ( - TopNotch.h, - ); - target = EAB4C7AE2D5AA7EB000CE23F /* TopNotch */; - }; - EAB4C7D92D5AA992000CE23F /* Exceptions for "TopNotchDemo" folder in "TopNotchDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = EAB4C7C72D5AA990000CE23F /* TopNotchDemo */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - EAB4C7B12D5AA7EB000CE23F /* TopNotch */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - EAB4C7B62D5AA7EB000CE23F /* Exceptions for "TopNotch" folder in "TopNotch" target */, - ); - path = TopNotch; - sourceTree = ""; - }; - EAB4C7C92D5AA990000CE23F /* TopNotchDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - EAB4C7D92D5AA992000CE23F /* Exceptions for "TopNotchDemo" folder in "TopNotchDemo" target */, - ); - path = TopNotchDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - EAB4C7AC2D5AA7EB000CE23F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EAB4C7C52D5AA990000CE23F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - EAB4C7DE2D5AAA26000CE23F /* TopNotch.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - EAB4C7A52D5AA7EB000CE23F = { - isa = PBXGroup; - children = ( - EAB4C7B12D5AA7EB000CE23F /* TopNotch */, - EAB4C7C92D5AA990000CE23F /* TopNotchDemo */, - EAB4C7DD2D5AAA26000CE23F /* Frameworks */, - EAB4C7B02D5AA7EB000CE23F /* Products */, - ); - sourceTree = ""; - }; - EAB4C7B02D5AA7EB000CE23F /* Products */ = { - isa = PBXGroup; - children = ( - EAB4C7AF2D5AA7EB000CE23F /* TopNotch.framework */, - EAB4C7C82D5AA990000CE23F /* TopNotchDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - EAB4C7DD2D5AAA26000CE23F /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - EAB4C7AA2D5AA7EB000CE23F /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - EAB4C7AE2D5AA7EB000CE23F /* TopNotch */ = { - isa = PBXNativeTarget; - buildConfigurationList = EAB4C7B72D5AA7EB000CE23F /* Build configuration list for PBXNativeTarget "TopNotch" */; - buildPhases = ( - EAB4C7AA2D5AA7EB000CE23F /* Headers */, - EAB4C7AB2D5AA7EB000CE23F /* Sources */, - EAB4C7AC2D5AA7EB000CE23F /* Frameworks */, - EAB4C7AD2D5AA7EB000CE23F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - EAB4C7B12D5AA7EB000CE23F /* TopNotch */, - ); - name = TopNotch; - packageProductDependencies = ( - ); - productName = TopNotch; - productReference = EAB4C7AF2D5AA7EB000CE23F /* TopNotch.framework */; - productType = "com.apple.product-type.framework"; - }; - EAB4C7C72D5AA990000CE23F /* TopNotchDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = EAB4C7DA2D5AA992000CE23F /* Build configuration list for PBXNativeTarget "TopNotchDemo" */; - buildPhases = ( - EAB4C7C42D5AA990000CE23F /* Sources */, - EAB4C7C52D5AA990000CE23F /* Frameworks */, - EAB4C7C62D5AA990000CE23F /* Resources */, - EAB4C7E22D5AAA26000CE23F /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - EAB4C7E12D5AAA26000CE23F /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - EAB4C7C92D5AA990000CE23F /* TopNotchDemo */, - ); - name = TopNotchDemo; - packageProductDependencies = ( - ); - productName = TopNotchDemo; - productReference = EAB4C7C82D5AA990000CE23F /* TopNotchDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - EAB4C7A62D5AA7EB000CE23F /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1610; - LastUpgradeCheck = 1610; - TargetAttributes = { - EAB4C7AE2D5AA7EB000CE23F = { - CreatedOnToolsVersion = 16.1; - }; - EAB4C7C72D5AA990000CE23F = { - CreatedOnToolsVersion = 16.1; - }; - }; - }; - buildConfigurationList = EAB4C7A92D5AA7EB000CE23F /* Build configuration list for PBXProject "TopNotch" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = EAB4C7A52D5AA7EB000CE23F; - minimizedProjectReferenceProxies = 1; - preferredProjectObjectVersion = 77; - productRefGroup = EAB4C7B02D5AA7EB000CE23F /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - EAB4C7AE2D5AA7EB000CE23F /* TopNotch */, - EAB4C7C72D5AA990000CE23F /* TopNotchDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - EAB4C7AD2D5AA7EB000CE23F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EAB4C7C62D5AA990000CE23F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - EAB4C7AB2D5AA7EB000CE23F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - EAB4C7C42D5AA990000CE23F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - EAB4C7E12D5AAA26000CE23F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = EAB4C7AE2D5AA7EB000CE23F /* TopNotch */; - targetProxy = EAB4C7E02D5AAA26000CE23F /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - EAB4C7B82D5AA7EB000CE23F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CG56CG5WCQ; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = gold.samhenri.TopNotch; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_PACKAGE_NAME = "$(TARGET_NAME:c99extidentifier)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - EAB4C7B92D5AA7EB000CE23F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = CG56CG5WCQ; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = gold.samhenri.TopNotch; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_PACKAGE_NAME = "$(TARGET_NAME:c99extidentifier)"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - EAB4C7BA2D5AA7EB000CE23F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - EAB4C7BB2D5AA7EB000CE23F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.1; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - EAB4C7DB2D5AA992000CE23F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = CG56CG5WCQ; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = TopNotchDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = gold.samhenri.TopNotchDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - EAB4C7DC2D5AA992000CE23F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = CG56CG5WCQ; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = TopNotchDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = gold.samhenri.TopNotchDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - EAB4C7A92D5AA7EB000CE23F /* Build configuration list for PBXProject "TopNotch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EAB4C7BA2D5AA7EB000CE23F /* Debug */, - EAB4C7BB2D5AA7EB000CE23F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EAB4C7B72D5AA7EB000CE23F /* Build configuration list for PBXNativeTarget "TopNotch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EAB4C7B82D5AA7EB000CE23F /* Debug */, - EAB4C7B92D5AA7EB000CE23F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - EAB4C7DA2D5AA992000CE23F /* Build configuration list for PBXNativeTarget "TopNotchDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - EAB4C7DB2D5AA992000CE23F /* Debug */, - EAB4C7DC2D5AA992000CE23F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = EAB4C7A62D5AA7EB000CE23F /* Project object */; -} diff --git a/TopNotch.xcodeproj/xcuserdata/shg.xcuserdatad/xcschemes/xcschememanagement.plist b/TopNotch.xcodeproj/xcuserdata/shg.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 4f73ec7..0000000 --- a/TopNotch.xcodeproj/xcuserdata/shg.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,19 +0,0 @@ - - - - - SchemeUserState - - TopNotch.xcscheme_^#shared#^_ - - orderHint - 1 - - TopNotchDemo.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/TopNotch/TopNotch.docc/TopNotch.md b/TopNotch/TopNotch.docc/TopNotch.md deleted file mode 100644 index 17b3e4c..0000000 --- a/TopNotch/TopNotch.docc/TopNotch.md +++ /dev/null @@ -1,42 +0,0 @@ -# ``TopNotch`` - -![TopNotch. Hide a message under the notch. It'll be our little secret.](./TopNotch/TopNotch.docc/Resources/banner.png) - -## Overview - -TopNotch is a lil Swift package that lets you **hide a custom view underneath the device’s notch**. Since it’ll only be visible in screenshots and screen recordings, you can have some fun. **Put a version string in there**, maybe use it as a branding moment to **stick your logo there**, write your darkest secrets, whatever your little heart desires. - -If you opt to actually write your little secrets there, you can set `shouldHideForTaskSwitcher` on `TopNotchConfiguration` to hide the view when `sceneWillDeactivateNotification` gets called. It'll come back after `sceneDidActivateNotification` is called or if you ask nicely. - -It automatically calculates the notch’s exclusion area (using an undocumented `_exclusionArea` property on UIScreen). Since it doesn't always return the right values for older notch styles, I'm applying some manual, device-specific adjustments to make sure it stays hidden on all devices. - -> [!WARNING] -> Because TopNotch relies on undocumented APIs, it may not be App Store safe. Give it a shot though. I dare you. - -https://github.com/user-attachments/assets/61dfcdc5-868a-45d6-91f1-aa0898211357 - - -## TODO -- Reduce logging pollution -- Make the SwiftUI adapter useful - -## Usage - -I've attached a little demo project if that's how you roll. TL;DR: - -```swift -// Create a custom view (or use your own) to display behind the notch. -let notchLabel = UILabel() -notchLabel.text = "Hi Mom" -notchLabel.textAlignment = .center -notchLabel.textColor = .white -notchLabel.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.7) - -// Show the notch view. -TopNotchManager.shared.show(customView: notchLabel, with: TopNotchConfiguration(animationDuration: 0.3, - shouldAnimate: true, - shouldHideForTaskSwitcher: true)) - -// To hide it: -TopNotchManager.shared.hide() -``` diff --git a/TopNotch/TopNotch.h b/TopNotch/TopNotch.h deleted file mode 100644 index fdaa385..0000000 --- a/TopNotch/TopNotch.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// TopNotch.h -// TopNotch -// -// Created by Sam Gold on 2025-02-10. -// - -#import - -//! Project version number for TopNotch. -FOUNDATION_EXPORT double TopNotchVersionNumber; - -//! Project version string for TopNotch. -FOUNDATION_EXPORT const unsigned char TopNotchVersionString[]; - -// In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/TopNotchDemo/AppDelegate.swift b/TopNotchDemo/AppDelegate.swift deleted file mode 100644 index 7e35c7e..0000000 --- a/TopNotchDemo/AppDelegate.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// AppDelegate.swift -// TopNotchDemo -// -// Created by Sam Gold on 2025-02-10. -// - -import UIKit - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } -} diff --git a/TopNotchDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/TopNotchDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb87897..0000000 --- a/TopNotchDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/TopNotchDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/TopNotchDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 2305880..0000000 --- a/TopNotchDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/TopNotchDemo/Assets.xcassets/Contents.json b/TopNotchDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c0059..0000000 --- a/TopNotchDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/TopNotchDemo/FontCollectionViewController.swift b/TopNotchDemo/FontCollectionViewController.swift deleted file mode 100644 index 81a59bd..0000000 --- a/TopNotchDemo/FontCollectionViewController.swift +++ /dev/null @@ -1,70 +0,0 @@ -// -// FontTableViewController.swift -// TopNotchDemo -// -// Created by Sam Gold on 2025-02-10. -// - -import UIKit -import TopNotch - -class FontTableViewController: UITableViewController { - - private let fontFamilies = UIFont.familyNames - - override init(style: UITableView.Style = .insetGrouped) { - super.init(style: style) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - self.title = "Font Families" - - tableView.register(UITableViewCell.self, forCellReuseIdentifier: "FontCell") - - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Show Modal", style: .plain, target: self, action: #selector(showModal)) - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - let watermarkConfig = TopNotchConfiguration(animationDuration: 0.3, - shouldAnimate: true, - shouldHideForTaskSwitcher: false) - - let notchLabel = UILabel() - notchLabel.text = "Top Notch!" - notchLabel.textColor = .white - notchLabel.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.7) - notchLabel.textAlignment = .center - - TopNotchManager.shared.show(customView: notchLabel, with: watermarkConfig) - } - - - // MARK: - Table view data source - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return fontFamilies.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - - let cell = tableView.dequeueReusableCell(withIdentifier: "FontCell", for: indexPath) - cell.textLabel?.text = fontFamilies[indexPath.row] - return cell - } - - // MARK: - Actions - - @objc private func showModal() { - let modalVC = ModalSheetViewController() - let nav = UINavigationController(rootViewController: modalVC) - nav.modalPresentationStyle = .automatic - present(nav, animated: true, completion: nil) - } -} diff --git a/TopNotchDemo/Info.plist b/TopNotchDemo/Info.plist deleted file mode 100644 index 0eb786d..0000000 --- a/TopNotchDemo/Info.plist +++ /dev/null @@ -1,23 +0,0 @@ - - - - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/TopNotchDemo/ModalSheetViewController.swift b/TopNotchDemo/ModalSheetViewController.swift deleted file mode 100644 index 7f66053..0000000 --- a/TopNotchDemo/ModalSheetViewController.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// ModalSheetViewController.swift -// TopNotchDemo -// -// Created by Sam Gold on 2025-02-10. -// - -import UIKit - -class ModalSheetViewController: UIViewController { - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .systemGroupedBackground - title = "Modal Sheet" - navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, - target: self, - action: #selector(dismissModal)) - } - - @objc private func dismissModal() { - dismiss(animated: true, completion: nil) - } -} diff --git a/TopNotchDemo/SceneDelegate.swift b/TopNotchDemo/SceneDelegate.swift deleted file mode 100644 index 1697f87..0000000 --- a/TopNotchDemo/SceneDelegate.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// SceneDelegate.swift -// TopNotchDemo -// -// Created by Sam Gold on 2025-02-10. -// - -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - func scene(_ scene: UIScene, - willConnectTo session: UISceneSession, - options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - - let window = UIWindow(windowScene: windowScene) - // Use the insetGrouped table view controller. - let fontTableVC = FontTableViewController() - let navController = UINavigationController(rootViewController: fontTableVC) - - window.rootViewController = navController - self.window = window - window.makeKeyAndVisible() - } -} From be2b84ddefada5b8c3d6714a198036ae0bee15e3 Mon Sep 17 00:00:00 2001 From: fanxinghua Date: Fri, 3 Jul 2026 18:09:16 +0800 Subject: [PATCH 4/5] Create README.md --- README.md | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..0bf9e68 --- /dev/null +++ b/README.md @@ -0,0 +1,56 @@ +# ``TopNotch`` + +![TopNotch. Hide a message under the notch. It'll be our little secret.](./TopNotch/TopNotch.docc/Resources/banner.png) + +## Overview + +TopNotch is a lil Swift package that lets you **hide a custom view underneath the device’s notch**. Since it’ll only be visible in screenshots and screen recordings, you can have some fun. **Put a version string in there**, maybe use it as a branding moment to **stick your logo there**, write your darkest secrets, whatever your little heart desires. + +If you opt to actually write your little secrets there, you can set `shouldHideForTaskSwitcher` on `TopNotchConfiguration` to hide the view when `sceneWillDeactivateNotification` gets called. It'll come back after `sceneDidActivateNotification` is called or if you ask nicely. + +It automatically calculates the notch’s exclusion area (using an undocumented `_exclusionArea` property on UIScreen). Since it doesn't always return the right values for older notch styles, I'm applying some manual, device-specific adjustments to make sure it stays hidden on all devices. + +> [!WARNING] +> Because TopNotch relies on undocumented APIs, it may not be App Store safe. Give it a shot though. I dare you. + +https://github.com/user-attachments/assets/61dfcdc5-868a-45d6-91f1-aa0898211357 + + +## TODO +- Reduce logging pollution +- Make the SwiftUI adapter useful + +## Usage + +I've attached a little demo project if that's how you roll. TL;DR: + +```swift +struct ContentView: View { + @Environment(\.scenePhase) private var scenePhase + var body: some View { + Text("Hello world!") + .padding() + .onChange(of: scenePhase) { + if scenePhase == .active { + showTopNotch() + } + } + } + + func showTopNotch() { + // Create a custom view (or use your own) to display behind the notch. + let notchLabel = UILabel() + notchLabel.text = "TopNotch" + notchLabel.textAlignment = .center + notchLabel.textColor = .white + notchLabel.backgroundColor = UIColor.systemBlue.withAlphaComponent(0.7) + + // Show the notch view. + TopNotchManager.shared.show(customView: notchLabel, with: .init(animationDuration: 0.3, + shouldAnimate: true, + shouldHideForTaskSwitcher: false)) + } +} +// To hide it: +TopNotchManager.shared.hide() +``` From 8a48686c1a54f85784b385f3773860a2584abc12 Mon Sep 17 00:00:00 2001 From: Xinghua Date: Fri, 3 Jul 2026 18:11:04 +0800 Subject: [PATCH 5/5] Fix image path in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bf9e68..5364c26 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ``TopNotch`` -![TopNotch. Hide a message under the notch. It'll be our little secret.](./TopNotch/TopNotch.docc/Resources/banner.png) +![TopNotch. Hide a message under the notch. It'll be our little secret.](/Resources/banner.png) ## Overview