Repository: MAJKFL/Welcome-Sheet Branch: main Commit: 93332013d325 Files: 61 Total size: 166.2 KB Directory structure: gitextract_z12ur_l3/ ├── .gitignore ├── .swiftpm/ │ └── xcode/ │ └── package.xcworkspace/ │ └── xcshareddata/ │ └── IDEWorkspaceChecks.plist ├── Demo/ │ ├── UIKit-Storyboard-WelcomeSheetDemo/ │ │ ├── Readme.md │ │ ├── UIKit-Storyboard-WelcomeSheetDemo/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AccentColor.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── gears.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── SceneDelegate.swift │ │ │ └── ViewController.swift │ │ └── UIKit-Storyboard-WelcomeSheetDemo.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ ├── UIKit-WelcomeSheetDemo/ │ │ ├── UIKit-WelcomeSheetDemo/ │ │ │ ├── AppDelegate.swift │ │ │ ├── Assets.xcassets/ │ │ │ │ ├── AccentColor.colorset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── AppIcon.appiconset/ │ │ │ │ │ └── Contents.json │ │ │ │ ├── Contents.json │ │ │ │ └── gears.imageset/ │ │ │ │ └── Contents.json │ │ │ ├── Base.lproj/ │ │ │ │ ├── LaunchScreen.storyboard │ │ │ │ └── Main.storyboard │ │ │ ├── Info.plist │ │ │ ├── SceneDelegate.swift │ │ │ └── ViewController.swift │ │ └── UIKit-WelcomeSheetDemo.xcodeproj/ │ │ ├── project.pbxproj │ │ └── project.xcworkspace/ │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata/ │ │ └── IDEWorkspaceChecks.plist │ └── WelcomeSheetDemo/ │ ├── Shared/ │ │ ├── Assets.xcassets/ │ │ │ ├── AccentColor.colorset/ │ │ │ │ └── Contents.json │ │ │ ├── AppIcon.appiconset/ │ │ │ │ └── Contents.json │ │ │ ├── Contents.json │ │ │ └── gears.imageset/ │ │ │ └── Contents.json │ │ ├── ContentView.swift │ │ ├── WelcomeSheetDemoApp.swift │ │ └── demo.json │ ├── WelcomeSheetDemo.xcodeproj/ │ │ └── project.pbxproj │ └── macOS/ │ └── macOS.entitlements ├── Documentation/ │ └── UIKit/ │ └── Readme.md ├── LICENSE ├── Package.swift ├── README.md └── Sources/ └── WelcomeSheet/ ├── Dimensions/ │ ├── iPadSheetDimensions.swift │ └── iPhoneDimensions.swift ├── Extensions/ │ ├── AnyView+Extensitons.swift │ ├── Color+Extensions.swift │ ├── UIColor+Extensions.swift │ └── UIImage+Extensions.swift ├── Models/ │ ├── UIWelcomeSheetPage.swift │ ├── UIWelcomeSheetPageRow.swift │ ├── WelcomeSheetPage.swift │ └── WelcomeSheetPageRow.swift ├── Views/ │ ├── HorizontalAlignment.swift │ ├── OptionalButtonView.swift │ ├── ScrollOnlyOnOverflow.swift │ ├── WelcomeSheetModal.swift │ ├── WelcomeSheetPageView.swift │ └── WelcomeSheetView.swift ├── WelcomeSheet.swift ├── WelcomeSheetController.swift └── WelcomeSheetStoryboardController.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .DS_Store /.build /Packages /*.xcodeproj xcuserdata/ DerivedData/ .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata ================================================ FILE: .swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/Readme.md ================================================ # UIKit Storyboard WelcomeSheet Demo For a step-by-step guide on how to configure by storyboards, please see the [Documentation](../../Documentation/UIKit/Readme.md) ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/AppDelegate.swift ================================================ // // AppDelegate.swift // UIKit-Storyboard-WelcomeSheetDemo // // Created by Eskil Gjerde Sviggum on 18/01/2023. // import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "color-space" : "display-p3", "components" : { "alpha" : "1.000", "blue" : "0.769", "green" : "0.682", "red" : "0.353" } }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "filename" : "1024.png", "idiom" : "universal", "platform" : "ios", "size" : "1024x1024" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Assets.xcassets/gears.imageset/Contents.json ================================================ { "images" : [ { "filename" : "settings-gears.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Base.lproj/Main.storyboard ================================================ Create lists to match your needs and categorize reminders with tags. Collaborate with others by sharing lists and assigning individual tasks. ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/Info.plist ================================================ UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UISceneStoryboardFile Main ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/SceneDelegate.swift ================================================ // // SceneDelegate.swift // UIKit-Storyboard-WelcomeSheetDemo // // Created by Eskil Gjerde Sviggum on 18/01/2023. // import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo/ViewController.swift ================================================ // // ViewController.swift // UIKit-Storyboard-WelcomeSheetDemo // // Created by Eskil Gjerde Sviggum on 18/01/2023. // import UIKit import WelcomeSheet class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if let welcomeSheetController = segue.destination as? WelcomeSheetStoryboardController { welcomeSheetController.delegate = self } } } extension ViewController: WelcomeSheetDelegate { func welcomeSheetController(didDismiss welcomeSheetController: UIViewController) { print("Did dismiss") } } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 56; objects = { /* Begin PBXBuildFile section */ 7B5F339A2978166000E957C1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F33992978166000E957C1 /* AppDelegate.swift */; }; 7B5F339C2978166000E957C1 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F339B2978166000E957C1 /* SceneDelegate.swift */; }; 7B5F339E2978166000E957C1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B5F339D2978166000E957C1 /* ViewController.swift */; }; 7B5F33A12978166000E957C1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B5F339F2978166000E957C1 /* Main.storyboard */; }; 7B5F33A32978166100E957C1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7B5F33A22978166100E957C1 /* Assets.xcassets */; }; 7B5F33A62978166100E957C1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7B5F33A42978166100E957C1 /* LaunchScreen.storyboard */; }; 7B5F33B12978170500E957C1 /* WelcomeSheet in Frameworks */ = {isa = PBXBuildFile; productRef = 7B5F33B02978170500E957C1 /* WelcomeSheet */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 7B5F33962978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "UIKit-Storyboard-WelcomeSheetDemo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 7B5F33992978166000E957C1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 7B5F339B2978166000E957C1 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 7B5F339D2978166000E957C1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 7B5F33A02978166000E957C1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 7B5F33A22978166100E957C1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 7B5F33A52978166100E957C1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 7B5F33A72978166100E957C1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 7B5F33AE297816BB00E957C1 /* Welcome-Sheet */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "Welcome-Sheet"; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 7B5F33932978166000E957C1 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 7B5F33B12978170500E957C1 /* WelcomeSheet in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 7B5F338D2978166000E957C1 = { isa = PBXGroup; children = ( 7B5F33AD297816BB00E957C1 /* Packages */, 7B5F33982978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo */, 7B5F33972978166000E957C1 /* Products */, 7B5F33AF2978170500E957C1 /* Frameworks */, ); sourceTree = ""; }; 7B5F33972978166000E957C1 /* Products */ = { isa = PBXGroup; children = ( 7B5F33962978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo.app */, ); name = Products; sourceTree = ""; }; 7B5F33982978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo */ = { isa = PBXGroup; children = ( 7B5F33992978166000E957C1 /* AppDelegate.swift */, 7B5F339B2978166000E957C1 /* SceneDelegate.swift */, 7B5F339D2978166000E957C1 /* ViewController.swift */, 7B5F339F2978166000E957C1 /* Main.storyboard */, 7B5F33A22978166100E957C1 /* Assets.xcassets */, 7B5F33A42978166100E957C1 /* LaunchScreen.storyboard */, 7B5F33A72978166100E957C1 /* Info.plist */, ); path = "UIKit-Storyboard-WelcomeSheetDemo"; sourceTree = ""; }; 7B5F33AD297816BB00E957C1 /* Packages */ = { isa = PBXGroup; children = ( 7B5F33AE297816BB00E957C1 /* Welcome-Sheet */, ); name = Packages; sourceTree = ""; }; 7B5F33AF2978170500E957C1 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 7B5F33952978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo */ = { isa = PBXNativeTarget; buildConfigurationList = 7B5F33AA2978166100E957C1 /* Build configuration list for PBXNativeTarget "UIKit-Storyboard-WelcomeSheetDemo" */; buildPhases = ( 7B5F33922978166000E957C1 /* Sources */, 7B5F33932978166000E957C1 /* Frameworks */, 7B5F33942978166000E957C1 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "UIKit-Storyboard-WelcomeSheetDemo"; packageProductDependencies = ( 7B5F33B02978170500E957C1 /* WelcomeSheet */, ); productName = "UIKit-Storyboard-WelcomeSheetDemo"; productReference = 7B5F33962978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 7B5F338E2978166000E957C1 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1420; LastUpgradeCheck = 1420; TargetAttributes = { 7B5F33952978166000E957C1 = { CreatedOnToolsVersion = 14.2; }; }; }; buildConfigurationList = 7B5F33912978166000E957C1 /* Build configuration list for PBXProject "UIKit-Storyboard-WelcomeSheetDemo" */; compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 7B5F338D2978166000E957C1; productRefGroup = 7B5F33972978166000E957C1 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 7B5F33952978166000E957C1 /* UIKit-Storyboard-WelcomeSheetDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 7B5F33942978166000E957C1 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 7B5F33A62978166100E957C1 /* LaunchScreen.storyboard in Resources */, 7B5F33A32978166100E957C1 /* Assets.xcassets in Resources */, 7B5F33A12978166000E957C1 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 7B5F33922978166000E957C1 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 7B5F339E2978166000E957C1 /* ViewController.swift in Sources */, 7B5F339A2978166000E957C1 /* AppDelegate.swift in Sources */, 7B5F339C2978166000E957C1 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 7B5F339F2978166000E957C1 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( 7B5F33A02978166000E957C1 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; 7B5F33A42978166100E957C1 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( 7B5F33A52978166100E957C1 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 7B5F33A82978166100E957C1 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; 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; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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 = 16.2; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 7B5F33A92978166100E957C1 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; 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; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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 = 16.2; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; 7B5F33AB2978166100E957C1 /* 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 = EUKTZ7725R; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "UIKit-Storyboard-WelcomeSheetDemo/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; 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 = "com.jakubflorek.UIKit-WelcomeSheetDemo.UIKit-Storyboard-WelcomeSheetDemo"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 7B5F33AC2978166100E957C1 /* 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 = EUKTZ7725R; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "UIKit-Storyboard-WelcomeSheetDemo/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; 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 = "com.jakubflorek.UIKit-WelcomeSheetDemo.UIKit-Storyboard-WelcomeSheetDemo"; 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 */ 7B5F33912978166000E957C1 /* Build configuration list for PBXProject "UIKit-Storyboard-WelcomeSheetDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 7B5F33A82978166100E957C1 /* Debug */, 7B5F33A92978166100E957C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 7B5F33AA2978166100E957C1 /* Build configuration list for PBXNativeTarget "UIKit-Storyboard-WelcomeSheetDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 7B5F33AB2978166100E957C1 /* Debug */, 7B5F33AC2978166100E957C1 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ 7B5F33B02978170500E957C1 /* WelcomeSheet */ = { isa = XCSwiftPackageProductDependency; productName = WelcomeSheet; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 7B5F338E2978166000E957C1 /* Project object */; } ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/UIKit-Storyboard-WelcomeSheetDemo/UIKit-Storyboard-WelcomeSheetDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/AppDelegate.swift ================================================ // // AppDelegate.swift // UIKit-WelcomeSheetDemo // // Created by Kevin Romero Peces-Barba on 6/10/22. // import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } // MARK: UISceneSession Lifecycle func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Called when a new scene session is being created. // Use this method to select a configuration to create the new scene with. return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { // Called when the user discards a scene session. // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "color-space" : "display-p3", "components" : { "alpha" : "1.000", "blue" : "0.769", "green" : "0.682", "red" : "0.353" } }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ { "images" : [ { "filename" : "40.png", "idiom" : "iphone", "scale" : "2x", "size" : "20x20" }, { "filename" : "60.png", "idiom" : "iphone", "scale" : "3x", "size" : "20x20" }, { "filename" : "29.png", "idiom" : "iphone", "scale" : "1x", "size" : "29x29" }, { "filename" : "58.png", "idiom" : "iphone", "scale" : "2x", "size" : "29x29" }, { "filename" : "87.png", "idiom" : "iphone", "scale" : "3x", "size" : "29x29" }, { "filename" : "80.png", "idiom" : "iphone", "scale" : "2x", "size" : "40x40" }, { "filename" : "120.png", "idiom" : "iphone", "scale" : "3x", "size" : "40x40" }, { "filename" : "57.png", "idiom" : "iphone", "scale" : "1x", "size" : "57x57" }, { "filename" : "114.png", "idiom" : "iphone", "scale" : "2x", "size" : "57x57" }, { "filename" : "120.png", "idiom" : "iphone", "scale" : "2x", "size" : "60x60" }, { "filename" : "180.png", "idiom" : "iphone", "scale" : "3x", "size" : "60x60" }, { "filename" : "20.png", "idiom" : "ipad", "scale" : "1x", "size" : "20x20" }, { "filename" : "40.png", "idiom" : "ipad", "scale" : "2x", "size" : "20x20" }, { "filename" : "29.png", "idiom" : "ipad", "scale" : "1x", "size" : "29x29" }, { "filename" : "58.png", "idiom" : "ipad", "scale" : "2x", "size" : "29x29" }, { "filename" : "40.png", "idiom" : "ipad", "scale" : "1x", "size" : "40x40" }, { "filename" : "80.png", "idiom" : "ipad", "scale" : "2x", "size" : "40x40" }, { "filename" : "50.png", "idiom" : "ipad", "scale" : "1x", "size" : "50x50" }, { "filename" : "100.png", "idiom" : "ipad", "scale" : "2x", "size" : "50x50" }, { "filename" : "72.png", "idiom" : "ipad", "scale" : "1x", "size" : "72x72" }, { "filename" : "144.png", "idiom" : "ipad", "scale" : "2x", "size" : "72x72" }, { "filename" : "76.png", "idiom" : "ipad", "scale" : "1x", "size" : "76x76" }, { "filename" : "152.png", "idiom" : "ipad", "scale" : "2x", "size" : "76x76" }, { "filename" : "167.png", "idiom" : "ipad", "scale" : "2x", "size" : "83.5x83.5" }, { "filename" : "1024.png", "idiom" : "ios-marketing", "scale" : "1x", "size" : "1024x1024" }, { "filename" : "16.png", "idiom" : "mac", "scale" : "1x", "size" : "16x16" }, { "filename" : "32.png", "idiom" : "mac", "scale" : "2x", "size" : "16x16" }, { "filename" : "32.png", "idiom" : "mac", "scale" : "1x", "size" : "32x32" }, { "filename" : "64.png", "idiom" : "mac", "scale" : "2x", "size" : "32x32" }, { "filename" : "128.png", "idiom" : "mac", "scale" : "1x", "size" : "128x128" }, { "filename" : "256.png", "idiom" : "mac", "scale" : "2x", "size" : "128x128" }, { "filename" : "256.png", "idiom" : "mac", "scale" : "1x", "size" : "256x256" }, { "filename" : "512.png", "idiom" : "mac", "scale" : "2x", "size" : "256x256" }, { "filename" : "512.png", "idiom" : "mac", "scale" : "1x", "size" : "512x512" }, { "filename" : "1024.png", "idiom" : "mac", "scale" : "2x", "size" : "512x512" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Assets.xcassets/gears.imageset/Contents.json ================================================ { "images" : [ { "filename" : "settings-gears.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Base.lproj/LaunchScreen.storyboard ================================================ ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Base.lproj/Main.storyboard ================================================ ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/Info.plist ================================================ UIApplicationSceneManifest UIApplicationSupportsMultipleScenes UISceneConfigurations UIWindowSceneSessionRoleApplication UISceneConfigurationName Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate UISceneStoryboardFile Main ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/SceneDelegate.swift ================================================ // // SceneDelegate.swift // UIKit-WelcomeSheetDemo // // Created by Kevin Romero Peces-Barba on 6/10/22. // import UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. // This occurs shortly after the scene enters the background, or when its session is discarded. // Release any resources associated with this scene that can be re-created the next time the scene connects. // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). } func sceneDidBecomeActive(_ scene: UIScene) { // Called when the scene has moved from an inactive state to an active state. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. } func sceneWillResignActive(_ scene: UIScene) { // Called when the scene will move from an active state to an inactive state. // This may occur due to temporary interruptions (ex. an incoming phone call). } func sceneWillEnterForeground(_ scene: UIScene) { // Called as the scene transitions from the background to the foreground. // Use this method to undo the changes made on entering the background. } func sceneDidEnterBackground(_ scene: UIScene) { // Called as the scene transitions from the foreground to the background. // Use this method to save data, release shared resources, and store enough scene-specific state information // to restore the scene back to its current state. } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo/ViewController.swift ================================================ // // ViewController.swift // UIKit-WelcomeSheetDemo // // Created by Kevin Romero Peces-Barba on 6/10/22. // import UIKit import WelcomeSheet class ViewController: UIViewController { @IBOutlet weak var showSheetButton: UIButton! let pages = [ WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ WelcomeSheetPageRow(imageSystemName: "rectangle.stack.fill.badge.plus", accentColor: .mint, title: "Quick Creation", content: "It's incredibly intuitive. Simply declare an array of pages filled with content."), WelcomeSheetPageRow(imageNamed: "gears", accentColor: .indigo, title: "Highly Customisable", content: "Match sheet's appearance to your app, link buttons, perform actions after dismissal."), WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", accentColor: .green, title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ], accentColor: .purple, optionalButtonTitle: "About Welcome Sheet...", optionalButtonURL: URL(string: "https://github.com/MAJKFL/Welcome-Sheet")), WelcomeSheetPage(title: "What's New in Translate", rows: [ WelcomeSheetPageRow(imageSystemName: "platter.2.filled.iphone", title: "Conversation Views", content: "Choose a side-by-side or face-to-face conversation view."), WelcomeSheetPageRow(imageSystemName: "mic.badge.plus", title: "Auto Translate", content: "Respond in conversations without tapping the microphone button."), WelcomeSheetPageRow(imageSystemName: "iphone", title: "System-Wide Translation", content: "Translate selected text anywhere on your iPhone.") ], mainButtonTitle: "Wassup?"), WelcomeSheetPage(title: "Welcome to Reminders", rows: [ WelcomeSheetPageRow(imageSystemName: "note.text.badge.plus", accentColor: .green, title: "Quick Creation", content: "Simply type, ask Siri, or use the quick toolbar to create reminders."), WelcomeSheetPageRow(imageSystemName: "rectangle.grid.2x2.fill", accentColor: .init(red: 0.00, green: 0.70, blue: 1.00), title: "Easy Organizing", content: "Create lists to match your needs and categorize reminders with tags. Collaborate with others by sharing lists and assigning individual tasks."), WelcomeSheetPageRow(imageSystemName: "lightbulb.fill", accentColor: .orange, title: "Suggestions and Smart Lists", content: "Suggestions help you organize quickly, and smart lists automatically group reminders.") ], accentColor: .blue), WelcomeSheetPage(title: "What's New in Maps", rows: [ WelcomeSheetPageRow(imageSystemName: "map.fill", accentColor: .green, title: "Updated Map Style", content: "An improved design makes it easier to navigate and explore the map."), WelcomeSheetPageRow(imageSystemName: "mappin.and.ellipse", accentColor: .red, title: "All-New Place Cards", content: "Completely redesigned place cards make it easier to learn about and interact with places."), WelcomeSheetPageRow(imageSystemName: "magnifyingglass", accentColor: .blue, title: "Improved Search", content: "Finding places is now easier with filters and automatic updates when you're browsing results on the map.") ], accentColor: .pink, mainButtonTitle: "Let's go!", optionalButtonTitle: "About Apple Maps & Privacy...", optionalButtonURL: URL(string: "https://apple.com")) ] override func viewDidLoad() { super.viewDidLoad() showSheetButton.addTarget(self, action: #selector(showSheet), for: .touchUpInside) } @objc func showSheet() { let sheetVC = WelcomeSheetController() sheetVC.pages = pages sheetVC.onDismiss = sheetDismissed present(sheetVC, animated: true) } func sheetDismissed() { print("Sheet dismissed") } } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 56; objects = { /* Begin PBXBuildFile section */ 7B01CE742986A9B40044CE1E /* WelcomeSheet in Frameworks */ = {isa = PBXBuildFile; productRef = 7B01CE732986A9B40044CE1E /* WelcomeSheet */; }; D757A23328EEB0CD00056497 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757A23228EEB0CD00056497 /* AppDelegate.swift */; }; D757A23528EEB0CD00056497 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757A23428EEB0CD00056497 /* SceneDelegate.swift */; }; D757A23728EEB0CD00056497 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D757A23628EEB0CD00056497 /* ViewController.swift */; }; D757A23A28EEB0CD00056497 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D757A23828EEB0CD00056497 /* Main.storyboard */; }; D757A23C28EEB0CE00056497 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D757A23B28EEB0CE00056497 /* Assets.xcassets */; }; D757A23F28EEB0CE00056497 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D757A23D28EEB0CE00056497 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 3A867362296E08A700ED9C49 /* WelcomeSheet */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = WelcomeSheet; path = ../..; sourceTree = ""; }; D757A22F28EEB0CD00056497 /* UIKit-WelcomeSheetDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "UIKit-WelcomeSheetDemo.app"; sourceTree = BUILT_PRODUCTS_DIR; }; D757A23228EEB0CD00056497 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; D757A23428EEB0CD00056497 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; D757A23628EEB0CD00056497 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; D757A23928EEB0CD00056497 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; D757A23B28EEB0CE00056497 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; D757A23E28EEB0CE00056497 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; D757A24028EEB0CE00056497 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; D757A24928EEB2F000056497 /* Welcome-Sheet */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "Welcome-Sheet"; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ D757A22C28EEB0CD00056497 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 7B01CE742986A9B40044CE1E /* WelcomeSheet in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D757A22628EEB0CC00056497 = { isa = PBXGroup; children = ( D757A23128EEB0CD00056497 /* UIKit-WelcomeSheetDemo */, D757A24828EEB2F000056497 /* Packages */, D757A23028EEB0CD00056497 /* Products */, D757A24A28EEB31000056497 /* Frameworks */, ); sourceTree = ""; }; D757A23028EEB0CD00056497 /* Products */ = { isa = PBXGroup; children = ( D757A22F28EEB0CD00056497 /* UIKit-WelcomeSheetDemo.app */, ); name = Products; sourceTree = ""; }; D757A23128EEB0CD00056497 /* UIKit-WelcomeSheetDemo */ = { isa = PBXGroup; children = ( D757A23228EEB0CD00056497 /* AppDelegate.swift */, D757A23428EEB0CD00056497 /* SceneDelegate.swift */, D757A23628EEB0CD00056497 /* ViewController.swift */, D757A23828EEB0CD00056497 /* Main.storyboard */, D757A23B28EEB0CE00056497 /* Assets.xcassets */, D757A23D28EEB0CE00056497 /* LaunchScreen.storyboard */, D757A24028EEB0CE00056497 /* Info.plist */, ); path = "UIKit-WelcomeSheetDemo"; sourceTree = ""; }; D757A24828EEB2F000056497 /* Packages */ = { isa = PBXGroup; children = ( D757A24928EEB2F000056497 /* Welcome-Sheet */, 3A867362296E08A700ED9C49 /* WelcomeSheet */, ); name = Packages; sourceTree = ""; }; D757A24A28EEB31000056497 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ D757A22E28EEB0CD00056497 /* UIKit-WelcomeSheetDemo */ = { isa = PBXNativeTarget; buildConfigurationList = D757A24328EEB0CE00056497 /* Build configuration list for PBXNativeTarget "UIKit-WelcomeSheetDemo" */; buildPhases = ( D757A22B28EEB0CD00056497 /* Sources */, D757A22C28EEB0CD00056497 /* Frameworks */, D757A22D28EEB0CD00056497 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "UIKit-WelcomeSheetDemo"; packageProductDependencies = ( 7B01CE732986A9B40044CE1E /* WelcomeSheet */, ); productName = "UIKit-WelcomeSheetDemo"; productReference = D757A22F28EEB0CD00056497 /* UIKit-WelcomeSheetDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D757A22728EEB0CC00056497 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1410; LastUpgradeCheck = 1410; TargetAttributes = { D757A22E28EEB0CD00056497 = { CreatedOnToolsVersion = 14.1; }; }; }; buildConfigurationList = D757A22A28EEB0CC00056497 /* Build configuration list for PBXProject "UIKit-WelcomeSheetDemo" */; compatibilityVersion = "Xcode 14.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = D757A22628EEB0CC00056497; productRefGroup = D757A23028EEB0CD00056497 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D757A22E28EEB0CD00056497 /* UIKit-WelcomeSheetDemo */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ D757A22D28EEB0CD00056497 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( D757A23F28EEB0CE00056497 /* LaunchScreen.storyboard in Resources */, D757A23C28EEB0CE00056497 /* Assets.xcassets in Resources */, D757A23A28EEB0CD00056497 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ D757A22B28EEB0CD00056497 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D757A23728EEB0CD00056497 /* ViewController.swift in Sources */, D757A23328EEB0CD00056497 /* AppDelegate.swift in Sources */, D757A23528EEB0CD00056497 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ D757A23828EEB0CD00056497 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( D757A23928EEB0CD00056497 /* Base */, ); name = Main.storyboard; sourceTree = ""; }; D757A23D28EEB0CE00056497 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( D757A23E28EEB0CE00056497 /* Base */, ); name = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ D757A24128EEB0CE00056497 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; 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; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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 = 16.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; D757A24228EEB0CE00056497 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; 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; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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 = 16.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; VALIDATE_PRODUCT = YES; }; name = Release; }; D757A24428EEB0CE00056497 /* 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 = T23P54M8LP; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "UIKit-WelcomeSheetDemo/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; 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 = "com.jakubflorek.UIKit-WelcomeSheetDemo"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; D757A24528EEB0CE00056497 /* 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 = T23P54M8LP; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = "UIKit-WelcomeSheetDemo/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; INFOPLIST_KEY_UIMainStoryboardFile = Main; 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 = "com.jakubflorek.UIKit-WelcomeSheetDemo"; 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 */ D757A22A28EEB0CC00056497 /* Build configuration list for PBXProject "UIKit-WelcomeSheetDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( D757A24128EEB0CE00056497 /* Debug */, D757A24228EEB0CE00056497 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D757A24328EEB0CE00056497 /* Build configuration list for PBXNativeTarget "UIKit-WelcomeSheetDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( D757A24428EEB0CE00056497 /* Debug */, D757A24528EEB0CE00056497 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ 7B01CE732986A9B40044CE1E /* WelcomeSheet */ = { isa = XCSwiftPackageProductDependency; productName = WelcomeSheet; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = D757A22728EEB0CC00056497 /* Project object */; } ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: Demo/UIKit-WelcomeSheetDemo/UIKit-WelcomeSheetDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist ================================================ IDEDidComputeMac32BitWarning ================================================ FILE: Demo/WelcomeSheetDemo/Shared/Assets.xcassets/AccentColor.colorset/Contents.json ================================================ { "colors" : [ { "color" : { "color-space" : "display-p3", "components" : { "alpha" : "1.000", "blue" : "0.769", "green" : "0.682", "red" : "0.353" } }, "idiom" : "universal" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/WelcomeSheetDemo/Shared/Assets.xcassets/AppIcon.appiconset/Contents.json ================================================ {"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"72x72","expected-size":"72","filename":"72.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"76x76","expected-size":"152","filename":"152.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"50x50","expected-size":"100","filename":"100.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"76x76","expected-size":"76","filename":"76.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"50x50","expected-size":"50","filename":"50.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"72x72","expected-size":"144","filename":"144.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"40x40","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"83.5x83.5","expected-size":"167","filename":"167.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"20x20","expected-size":"20","filename":"20.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"1x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"ipad","scale":"2x"},{"size":"128x128","expected-size":"128","filename":"128.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"256x256","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"128x128","expected-size":"256","filename":"256.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"256x256","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"512x512","expected-size":"512","filename":"512.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"16","filename":"16.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"1x"},{"size":"16x16","expected-size":"32","filename":"32.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"32x32","expected-size":"64","filename":"64.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"},{"size":"512x512","expected-size":"1024","filename":"1024.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"mac","scale":"2x"}]} ================================================ FILE: Demo/WelcomeSheetDemo/Shared/Assets.xcassets/Contents.json ================================================ { "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/WelcomeSheetDemo/Shared/Assets.xcassets/gears.imageset/Contents.json ================================================ { "images" : [ { "filename" : "settings-gears.png", "idiom" : "universal", "scale" : "1x" }, { "idiom" : "universal", "scale" : "2x" }, { "idiom" : "universal", "scale" : "3x" } ], "info" : { "author" : "xcode", "version" : 1 } } ================================================ FILE: Demo/WelcomeSheetDemo/Shared/ContentView.swift ================================================ // // ContentView.swift // Shared // // Created by Jakub Florek on 27/11/2021. // import SwiftUI import WelcomeSheet struct ContentView: View { @State private var showSheet = false var body: some View { Button("Show sheet") { showSheet.toggle() } .padding() .welcomeSheet(isPresented: $showSheet, onDismiss: { sheetDismissed() }, isSlideToDismissDisabled: true, pages: getPages()) // Sheet from page array // .welcomeSheet(isPresented: $showSheet, onDismiss: { sheetDismissed() }, isSlideToDismissDisabled: true, pages: getPagesFromJSON()) // Sheet from JSON } func sheetDismissed() { print("Sheet dismissed") } func getPages() -> [WelcomeSheetPage] { [WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ WelcomeSheetPageRow(imageSystemName: "rectangle.stack.fill.badge.plus", accentColor: Color.mint, title: "Quick Creation", content: "It's incredibly intuitive. Simply declare an array of pages filled with content."), WelcomeSheetPageRow(imageNamed: "gears", accentColor: Color.indigo, title: "Highly Customisable", content: "Match sheet's appearance to your app, link buttons, perform actions after dismissal."), WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", accentColor: Color.green, title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ], accentColor: Color.purple, optionalButtonTitle: "About Welcome Sheet...", optionalButtonURL: URL(string: "https://github.com/MAJKFL/Welcome-Sheet")), WelcomeSheetPage(title: "What's New in Translate", rows: [ WelcomeSheetPageRow(imageSystemName: "platter.2.filled.iphone", title: "Conversation Views", content: "Choose a side-by-side or face-to-face conversation view."), WelcomeSheetPageRow(imageSystemName: "mic.badge.plus", title: "Auto Translate", content: "Respond in conversations without tapping the microphone button."), WelcomeSheetPageRow(imageSystemName: "iphone", title: "System-Wide Translation", content: "Translate selected text anywhere on your iPhone.") ], mainButtonTitle: "Wassup?"), WelcomeSheetPage(title: "Welcome to Reminders", rows: [ WelcomeSheetPageRow(imageSystemName: "note.text.badge.plus", accentColor: Color.green, title: "Quick Creation", content: "Simply type, ask Siri, or use the quick toolbar to create reminders."), WelcomeSheetPageRow(imageSystemName: "rectangle.grid.2x2.fill", accentColor: Color(red: 0.00, green: 0.70, blue: 1.00), title: "Easy Organizing", content: "Create lists to match your needs and categorize reminders with tags. Collaborate with others by sharing lists and assigning individual tasks."), WelcomeSheetPageRow(imageSystemName: "lightbulb.fill", accentColor: Color.orange, title: "Suggestions and Smart Lists", content: "Suggestions help you organize quickly, and smart lists automatically group reminders.") ], accentColor: Color.blue, optionalButtonTitle: "Show Terms and Conditions", optionalButtonView: { Text("Terms and Conditions") }), WelcomeSheetPage(title: "What's New in Maps", rows: [ WelcomeSheetPageRow(imageSystemName: "map.fill", accentColor: Color.green, title: "Updated Map Style", content: "An improved design makes it easier to navigate and explore the map."), WelcomeSheetPageRow(imageSystemName: "mappin.and.ellipse", accentColor: Color.red, title: "All-New Place Cards", content: "Completely redesigned place cards make it easier to learn about and interact with places."), WelcomeSheetPageRow(imageSystemName: "magnifyingglass", accentColor: Color.blue, title: "Improved Search", content: "Finding places is now easier with filters and automatic updates when you're browsing results on the map.") ], accentColor: Color.pink, mainButtonTitle: "Let's go!", optionalButtonTitle: "About Apple Maps & Privacy...", optionalButtonURL: URL(string: "https://apple.com")) ] } func getPagesFromJSON() -> [WelcomeSheetPage] { if let url = Bundle.main.url(forResource: "demo", withExtension: "json") { do { let jsonData = try Data(contentsOf: url) let decoder = JSONDecoder() return try decoder.decode([WelcomeSheetPage].self, from: jsonData) } catch { print(error) } } return [] } } ================================================ FILE: Demo/WelcomeSheetDemo/Shared/WelcomeSheetDemoApp.swift ================================================ // // WelcomeSheetDemoApp.swift // Shared // // Created by Jakub Florek on 27/11/2021. // import SwiftUI @main struct WelcomeSheetDemoApp: App { var body: some Scene { WindowGroup { ContentView() } } } ================================================ FILE: Demo/WelcomeSheetDemo/Shared/demo.json ================================================ [ { "optionalButtonURL":"https:\/\/github.com\/MAJKFL\/Welcome-Sheet", "accentColor":"BF5AF2", "isShowingOptionalButton":true, "title":"Welcome to Welcome Sheet", "rows":[ { "accentColor":"63E6E1", "title":"Quick Creation", "content":"Sheet creation is incredibly intuitive. Simply create an array of pages filled with your content.", "imageName":"rectangle.stack.fill.badge.plus" }, { "accentColor":"5E5CE6", "title":"Highly Customizable", "content":"Set accent colors, add optional buttons, disable dismiss gestures, perform actions after button taps or sheet dismissal and more!", "imageName":"gears" }, { "accentColor":"30D158", "title":"Works out of the box", "content":"Don't worry about different screen sizes. Your Welcome Sheet will look gorgeous on every iOS device!", "imageName":"ipad.and.iphone" } ], "optionalButtonTitle":"About Welcome Sheet...", "mainButtonTitle":"Continue" } ] ================================================ FILE: Demo/WelcomeSheetDemo/WelcomeSheetDemo.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 55; objects = { /* Begin PBXBuildFile section */ 3A1EC3972752B0E70005F216 /* WelcomeSheetDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1EC3872752B0E70005F216 /* WelcomeSheetDemoApp.swift */; }; 3A1EC3982752B0E70005F216 /* WelcomeSheetDemoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1EC3872752B0E70005F216 /* WelcomeSheetDemoApp.swift */; }; 3A1EC3992752B0E70005F216 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1EC3882752B0E70005F216 /* ContentView.swift */; }; 3A1EC39A2752B0E70005F216 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1EC3882752B0E70005F216 /* ContentView.swift */; }; 3A1EC39B2752B0E70005F216 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A1EC3892752B0E70005F216 /* Assets.xcassets */; }; 3A1EC39C2752B0E70005F216 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3A1EC3892752B0E70005F216 /* Assets.xcassets */; }; 3A75F403275D1E30009E94E6 /* demo.json in Resources */ = {isa = PBXBuildFile; fileRef = 3A75F402275D1E30009E94E6 /* demo.json */; }; 3A75F404275D1E30009E94E6 /* demo.json in Resources */ = {isa = PBXBuildFile; fileRef = 3A75F402275D1E30009E94E6 /* demo.json */; }; D74557F528EEBA6E0025C195 /* WelcomeSheet in Frameworks */ = {isa = PBXBuildFile; productRef = D74557F428EEBA6E0025C195 /* WelcomeSheet */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 3A1EC3872752B0E70005F216 /* WelcomeSheetDemoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeSheetDemoApp.swift; sourceTree = ""; }; 3A1EC3882752B0E70005F216 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 3A1EC3892752B0E70005F216 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 3A1EC38E2752B0E70005F216 /* WelcomeSheetDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WelcomeSheetDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3A1EC3942752B0E70005F216 /* WelcomeSheetDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WelcomeSheetDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3A1EC3962752B0E70005F216 /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = ""; }; 3A75F402275D1E30009E94E6 /* demo.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = demo.json; sourceTree = ""; }; D74557F228EEBA560025C195 /* Welcome-Sheet */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "Welcome-Sheet"; path = ../..; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 3A1EC38B2752B0E70005F216 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( D74557F528EEBA6E0025C195 /* WelcomeSheet in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A1EC3912752B0E70005F216 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 3A1EC3812752B0E70005F216 = { isa = PBXGroup; children = ( 3A1EC3862752B0E70005F216 /* Shared */, 3A1EC3952752B0E70005F216 /* macOS */, D74557F128EEBA560025C195 /* Packages */, 3A1EC38F2752B0E70005F216 /* Products */, D74557F328EEBA6E0025C195 /* Frameworks */, ); sourceTree = ""; }; 3A1EC3862752B0E70005F216 /* Shared */ = { isa = PBXGroup; children = ( 3A75F402275D1E30009E94E6 /* demo.json */, 3A1EC3872752B0E70005F216 /* WelcomeSheetDemoApp.swift */, 3A1EC3882752B0E70005F216 /* ContentView.swift */, 3A1EC3892752B0E70005F216 /* Assets.xcassets */, ); path = Shared; sourceTree = ""; }; 3A1EC38F2752B0E70005F216 /* Products */ = { isa = PBXGroup; children = ( 3A1EC38E2752B0E70005F216 /* WelcomeSheetDemo.app */, 3A1EC3942752B0E70005F216 /* WelcomeSheetDemo.app */, ); name = Products; sourceTree = ""; }; 3A1EC3952752B0E70005F216 /* macOS */ = { isa = PBXGroup; children = ( 3A1EC3962752B0E70005F216 /* macOS.entitlements */, ); path = macOS; sourceTree = ""; }; D74557F128EEBA560025C195 /* Packages */ = { isa = PBXGroup; children = ( D74557F228EEBA560025C195 /* Welcome-Sheet */, ); name = Packages; sourceTree = ""; }; D74557F328EEBA6E0025C195 /* Frameworks */ = { isa = PBXGroup; children = ( ); name = Frameworks; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 3A1EC38D2752B0E70005F216 /* WelcomeSheetDemo (iOS) */ = { isa = PBXNativeTarget; buildConfigurationList = 3A1EC39F2752B0E70005F216 /* Build configuration list for PBXNativeTarget "WelcomeSheetDemo (iOS)" */; buildPhases = ( 3A1EC38A2752B0E70005F216 /* Sources */, 3A1EC38B2752B0E70005F216 /* Frameworks */, 3A1EC38C2752B0E70005F216 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "WelcomeSheetDemo (iOS)"; packageProductDependencies = ( D74557F428EEBA6E0025C195 /* WelcomeSheet */, ); productName = "WelcomeSheetDemo (iOS)"; productReference = 3A1EC38E2752B0E70005F216 /* WelcomeSheetDemo.app */; productType = "com.apple.product-type.application"; }; 3A1EC3932752B0E70005F216 /* WelcomeSheetDemo (macOS) */ = { isa = PBXNativeTarget; buildConfigurationList = 3A1EC3A22752B0E70005F216 /* Build configuration list for PBXNativeTarget "WelcomeSheetDemo (macOS)" */; buildPhases = ( 3A1EC3902752B0E70005F216 /* Sources */, 3A1EC3912752B0E70005F216 /* Frameworks */, 3A1EC3922752B0E70005F216 /* Resources */, ); buildRules = ( ); dependencies = ( ); name = "WelcomeSheetDemo (macOS)"; productName = "WelcomeSheetDemo (macOS)"; productReference = 3A1EC3942752B0E70005F216 /* WelcomeSheetDemo.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 3A1EC3822752B0E70005F216 /* Project object */ = { isa = PBXProject; attributes = { BuildIndependentTargetsInParallel = 1; LastSwiftUpdateCheck = 1310; LastUpgradeCheck = 1320; TargetAttributes = { 3A1EC38D2752B0E70005F216 = { CreatedOnToolsVersion = 13.1; }; 3A1EC3932752B0E70005F216 = { CreatedOnToolsVersion = 13.1; }; }; }; buildConfigurationList = 3A1EC3852752B0E70005F216 /* Build configuration list for PBXProject "WelcomeSheetDemo" */; compatibilityVersion = "Xcode 13.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, Base, ); mainGroup = 3A1EC3812752B0E70005F216; packageReferences = ( ); productRefGroup = 3A1EC38F2752B0E70005F216 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( 3A1EC38D2752B0E70005F216 /* WelcomeSheetDemo (iOS) */, 3A1EC3932752B0E70005F216 /* WelcomeSheetDemo (macOS) */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 3A1EC38C2752B0E70005F216 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A75F403275D1E30009E94E6 /* demo.json in Resources */, 3A1EC39B2752B0E70005F216 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A1EC3922752B0E70005F216 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A75F404275D1E30009E94E6 /* demo.json in Resources */, 3A1EC39C2752B0E70005F216 /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 3A1EC38A2752B0E70005F216 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A1EC3992752B0E70005F216 /* ContentView.swift in Sources */, 3A1EC3972752B0E70005F216 /* WelcomeSheetDemoApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; 3A1EC3902752B0E70005F216 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 3A1EC39A2752B0E70005F216 /* ContentView.swift in Sources */, 3A1EC3982752B0E70005F216 /* WelcomeSheetDemoApp.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 3A1EC39D2752B0E70005F216 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; 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; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; }; name = Debug; }; 3A1EC39E2752B0E70005F216 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; CLANG_CXX_LIBRARY = "libc++"; 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; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; 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; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-O"; }; name = Release; }; 3A1EC3A02752B0E70005F216 /* 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 = 9RS6NWG958; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.florekjakub.WelcomeSheetDemo; PRODUCT_NAME = WelcomeSheetDemo; SDKROOT = iphoneos; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; }; 3A1EC3A12752B0E70005F216 /* 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 = 9RS6NWG958; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchScreen_Generation = YES; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", ); MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.florekjakub.WelcomeSheetDemo; PRODUCT_NAME = WelcomeSheetDemo; SDKROOT = iphoneos; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; name = Release; }; 3A1EC3A32752B0E70005F216 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 9RS6NWG958; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.florekjakub.WelcomeSheetDemo; PRODUCT_NAME = WelcomeSheetDemo; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Debug; }; 3A1EC3A42752B0E70005F216 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = macOS/macOS.entitlements; CODE_SIGN_IDENTITY = "-"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; CURRENT_PROJECT_VERSION = 1; DEVELOPMENT_TEAM = 9RS6NWG958; ENABLE_HARDENED_RUNTIME = YES; ENABLE_PREVIEWS = YES; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_KEY_NSHumanReadableCopyright = ""; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.0; MARKETING_VERSION = 1.0; PRODUCT_BUNDLE_IDENTIFIER = com.florekjakub.WelcomeSheetDemo; PRODUCT_NAME = WelcomeSheetDemo; SDKROOT = macosx; SWIFT_EMIT_LOC_STRINGS = YES; SWIFT_VERSION = 5.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 3A1EC3852752B0E70005F216 /* Build configuration list for PBXProject "WelcomeSheetDemo" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A1EC39D2752B0E70005F216 /* Debug */, 3A1EC39E2752B0E70005F216 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3A1EC39F2752B0E70005F216 /* Build configuration list for PBXNativeTarget "WelcomeSheetDemo (iOS)" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A1EC3A02752B0E70005F216 /* Debug */, 3A1EC3A12752B0E70005F216 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 3A1EC3A22752B0E70005F216 /* Build configuration list for PBXNativeTarget "WelcomeSheetDemo (macOS)" */ = { isa = XCConfigurationList; buildConfigurations = ( 3A1EC3A32752B0E70005F216 /* Debug */, 3A1EC3A42752B0E70005F216 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ /* Begin XCSwiftPackageProductDependency section */ D74557F428EEBA6E0025C195 /* WelcomeSheet */ = { isa = XCSwiftPackageProductDependency; productName = WelcomeSheet; }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 3A1EC3822752B0E70005F216 /* Project object */; } ================================================ FILE: Demo/WelcomeSheetDemo/macOS/macOS.entitlements ================================================ com.apple.security.app-sandbox com.apple.security.files.user-selected.read-only ================================================ FILE: Documentation/UIKit/Readme.md ================================================ # Configuring from Storyboards You can set up the pages of your Welcome Sheet from a Storyboard or XIB file—without writing a single line of code. Check out the [demo](../../Demo/UIKit-Storyboard-WelcomeSheetDemo/) for more details. ## Creating a WelcomeSheetStoryboardController Drag out a new UIViewController and set the class to `WelcomeSheetStoryboardController`.
A new UIViewController Set class of the controller to WelcomeSheetStoryboardController
## Creating a page - Create a new object and set the class to `UIWelcomeSheetPage`.
A new Object Set class of the object to UIWelcomeSheetPage
- Go to the *Attributes* tab and configure the page. Configure the attributes of a page ### Adding a row to the page - Create a new object and set the class to `UIWelcomeSheetPageRow`.
A new Object Set class of the object to UIWelcomeSheetPageRow
- Go to the *Attributes* tab and configure the row. Configure the attributes of a page row - Go to the *Connections* tab of your *page* and connect the `rows` outlet collection to all of the rows for the page. Connect the rows for your page ### Connecting a page to the controller - On your controller, go to the *Connections* tab and make a connection for each of your pages. Connect the pages for your welcome sheet ## Summary To configure your Welcome sheet from a storyboard do as follows: - Drag out a new UIViewController and set the class to `WelcomeSheetStoryboardController`. - For each of your pages: - Drag out a new Object and set the class to `UIWelcomeSheetPage`. - Configure the attributes - For each of the rows in your page: - Drag out a new Object and set the class to `UIWelcomeSheetPageRow`. - Configure the attributes - Connect the row to your page by draging out a connection to the `rows` outlet. - Connect the page to your sheet by draging out a connection to the `pages` outlet. - You now have a Welcome Sheet without writing a single line of code! You should end up with a lot of objects like so: Objects connected to your sheet # Using a System Symbol in a UIImage Due to conversion issues between `UIImage` and SwiftUI’s `Image`, system symbols will have a squashed appearance. Welcome Sheet overcomes this issue by obtaining the name of the system symbol from the `UIImage` and creating a new `Image` from the system name. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Jakub Florek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Package.swift ================================================ // swift-tools-version:5.5 // The swift-tools-version declares the minimum version of Swift required to build this package. import PackageDescription let package = Package( name: "WelcomeSheet", platforms: [.iOS(.v13)], products: [ // Products define the executables and libraries a package produces, and make them visible to other packages. .library( name: "WelcomeSheet", targets: ["WelcomeSheet"]), ], dependencies: [ // Dependencies declare other packages that this package depends on. // .package(url: /* package url */, from: "1.0.0"), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "WelcomeSheet", dependencies: []), ] ) ================================================ FILE: README.md ================================================ # Welcome Sheet ![Welcome Sheet baner](Documentation/WelcomeSheetBanner.png) Welcome sheet for iOS enables incredibly easy way for creating onboarding screens, update notes, or whatever you imagine! The main idea standing behind this project was to follow the design of Apple’s native onboarding screens as much as possible, that’s why you can be always sure they will look gorgeous on iPhone SE screen as well as on iPad Pro’s massive 12,9” display!

# SwiftUI To create a welcome sheet in SwiftUI simply add .welcomeSheet view modifier to your view and pass page array as an argument. ```swift import SwiftUI import WelcomeSheet struct ContentView: View { @State private var showSheet = false let pages = [ WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ WelcomeSheetPageRow(imageSystemName: "rectangle.stack.fill.badge.plus", title: "Quick Creation", content: "It's incredibly intuitive. Simply declare an array of pages filled with content."), WelcomeSheetPageRow(imageSystemName: "slider.horizontal.3", title: "Highly Customisable", content: "Match sheet's appearance to your app, link buttons, perform actions after dismissal."), WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ]) ] var body: some View { Button("Show sheet") { showSheet.toggle() } .welcomeSheet(isPresented: $showSheet, pages: pages) } } ``` ## .welcomeSheet `.welcomeSheet` presents welcome sheet with given pages when a binding to a Boolean value that you provide is true. ```swift .welcomeSheet(isPresented: $showSheet, onDismiss: { /* Run this code when sheet is dismissed */ }, isSlideToDismissDisabled: true, preferredColorScheme = .dark, pages: pages) ``` - `isPresented` - `bool` binding. When set to `true` presents sheet. - `onDismiss` - Closure called after sheet's dismissal. - `isSlideToDismissDisabled` - When set to `true` disables sheet's swipe to dismiss gesture. - `preferredColorScheme` - Overrides the default color scheme. - `pages` - Array of pages to be displayed chronologically. # UIKit To create a welcome sheet in UIKit create `WelcomeSheetController` and present it from your ViewController. ```Swift class ViewController: UIViewController { @IBOutlet weak var showSheetButton: UIButton! let pages = [ WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ WelcomeSheetPageRow(imageSystemName: "rectangle.stack.fill.badge.plus", title: "Quick Creation", content: "It's incredibly intuitive. Simply declare an array of pages filled with content."), WelcomeSheetPageRow(imageSystemName: "slider.horizontal.3", title: "Highly Customisable", content: "Match sheet's appearance to your app, link buttons, perform actions after dismissal."), WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ]) ] override func viewDidLoad() { super.viewDidLoad() showSheetButton.addTarget(self, action: #selector(showSheet), for: .touchUpInside) } @objc func showSheet() { let sheetVC = WelcomeSheetController() sheetVC.pages = pages sheetVC.onDismiss = sheetDismissed present(sheetVC, animated: true) } func sheetDismissed() { print("Sheet dismissed") } } ``` ## WelcomeSheetController `WelcomeSheetController` controller used to create, configure and present the sheet. ```Swift let sheetVC = WelcomeSheetController() sheetVC.pages = pages sheetVC.onDismiss = { /* Run this code when sheet is dismissed */ } sheetVC.isModalInPresentation = true present(sheetVC, animated: true) ``` - `pages` - Array of pages to be displayed chronologically. - `onDismiss` - Closure called after sheet's dismissal. - `isModalInPresentation` - When set to `true` disables sheet's swipe to dismiss gesture. # Models Objects used to configure sheets. Each model has also a set of UIKit data initializers. ## WelcomeSheetPage `WelcomeSheetPage` type that describes page's content. ```swift WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ // Rows ], mainButtonTitle: "Let's go!", accentColor: Color.purple, optionalButtonTitle: "About Welcome Sheet...", optionalButtonURL: URL(string: "https://github.com/MAJKFL/Welcome-Sheet")) ``` - `title` - Large title displayed on the top. - `rows` - Rows of content inside a body - `mainButtonTitle` - Optional title for a main button. Set to `"Continue"` by default. - `accentColor` - Color used for buttons. When set to `nil`, uses default accent colour. - `optionalButtonTitle` - Title for an optional button. - `optionalButtonURL` - `URL` to open when an optional button is pressed. ## WelcomeSheetPageRow `WelcomeSheetPageRow` describes row's content. ```swift WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", // Or `image: Image("ExampleImageName")` accentColor: Color.green, title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ``` - `imageSystemName` - SF Symbol name for image displayed at the beginning of a row. - `image` - Image displayed at the beginning of a row. - `accentColor` - Color used for an image. When set to `nil`, uses default accent colour. - `title` - Title displayed over a content. - `content` - Text displayed beneath a title. ## Decodable support You can decode pages from JSON. ```JSON [ { "optionalButtonURL":"https:\/\/github.com\/MAJKFL\/Welcome-Sheet", "accentColor":"BF5AF2", "isShowingOptionalButton":true, "title":"Welcome to Welcome Sheet", "rows":[ { "accentColor":"63E6E1", "title":"Quick Creation", "content":"Sheet creation is incredibly intuitive. Simply create an array of pages filled with your content.", "imageName":"rectangle.stack.fill.badge.plus" }, { "accentColor":"5E5CE6", "title":"Highly Customizable", "content":"Set accent colors, add optional buttons, disable dismiss gestures, perform actions after button taps or sheet dismissal and more!", "imageName":"gears" }, { "accentColor":"30D158", "title":"Works out of the box", "content":"Don't worry about different screen sizes. Your Welcome Sheet will look gorgeous on every iOS device!", "imageName":"ipad.and.iphone" } ], "optionalButtonTitle":"About Welcome Sheet...", "mainButtonTitle":"Continue" } ] ``` **Note:** `imageName` can store asset catalogue image name or SF Symbol name. ## UIKit Storyboards support You can configure your Welcome Sheet without writing a single line of code. ![Configuring Welcome Sheet from a Storyboard](Documentation/UIKit/Resources/Teaser.png) For a step-by-step guide on how to configure by storyboards, please see the [Documentation](Documentation/UIKit/Readme.md) ## Installation Using Swift Package Manager ``` .package(url: "https://github.com/MAJKFL/Welcome-Sheet", from: "0.1.1"), ``` ## Example ``` Swift import SwiftUI import WelcomeSheet struct ContentView: View { @State private var showSheet = false let pages = [ WelcomeSheetPage(title: "Welcome to Welcome Sheet", rows: [ WelcomeSheetPageRow(imageSystemName: "rectangle.stack.fill.badge.plus", accentColor: Color.mint, title: "Quick Creation", content: "It's incredibly intuitive. Simply declare an array of pages filled with content."), WelcomeSheetPageRow(imageSystemName: "slider.horizontal.3", accentColor: Color.indigo, title: "Highly Customisable", content: "Match sheet's appearance to your app, link buttons, perform actions after dismissal."), WelcomeSheetPageRow(imageSystemName: "ipad.and.iphone", accentColor: Color.green, title: "Works out of the box", content: "Don't worry about various screen sizes. It will look gorgeous on every iOS device.") ], accentColor: Color.purple, optionalButtonTitle: "About Welcome Sheet...", optionalButtonURL: URL(string: "https://github.com/MAJKFL/Welcome-Sheet")), WelcomeSheetPage(title: "What's New in Translate", rows: [ WelcomeSheetPageRow(imageSystemName: "platter.2.filled.iphone", title: "Conversation Views", content: "Choose a side-by-side or face-to-face conversation view."), WelcomeSheetPageRow(imageSystemName: "mic.badge.plus", title: "Auto Translate", content: "Respond in conversations without tapping the microphone button."), WelcomeSheetPageRow(imageSystemName: "iphone", title: "System-Wide Translation", content: "Translate selected text anywhere on your iPhone.") ], mainButtonTitle: "Wassup?") ] var body: some View { Button("Show sheet") { showSheet.toggle() } .welcomeSheet(isPresented: $showSheet, onDismiss: { print("Sheet dismissed") }, isSlideToDismissDisabled: true, pages: pages) } } ``` ================================================ FILE: Sources/WelcomeSheet/Dimensions/iPadSheetDimensions.swift ================================================ // // iPadSheetDimensions.swift // // // Created by Jakub Florek on 29/11/2021. // import SwiftUI struct iPadSheetDimensions { static var width: CGFloat { let width = UIScreen.main.bounds.width if width >= 1024 { // iPad pro 12.9" return width / 1.65 } else if width == 744 || width == 768 { // iPad mini (6th gen), older iPads return width / 1.2 } else if width > 810 { // iPads bigger than standard iPad return width / 1.35 } else { // The rest return width / 1.3 } } static var height: CGFloat { let height = UIScreen.main.bounds.height if height >= 1366 { // iPad pro 12.9" return height / 1.65 } else if height == 1133 { // iPad mini (6th gen) return height / 1.7 } else if height > 1080 { // iPads bigger than standard iPad return height / 1.6 } else { // The rest return height / 1.5 } } } ================================================ FILE: Sources/WelcomeSheet/Dimensions/iPhoneDimensions.swift ================================================ // // iPhoneDimensions.swift // // // Created by Jakub Florek on 29/11/2021. // import SwiftUI struct iPhoneDimensions { static let screenHeight = UIScreen.main.bounds.height static var spacing: CGFloat { if UIScreen.main.nativeBounds.height == 2340 || screenHeight < 736 { // iPhone mini, Smaller than iPhone plus return 30 } else { // The rest return 60 } } static var topPadding: CGFloat { if screenHeight == 568 { // iPhone SE 1st gen return 50 } else if screenHeight <= 736 { // Smaller than iPhone plus return 60 } else { // The rest return 80 } } static var horizontalPaddingAddend: CGFloat { if screenHeight * UIScreen.main.nativeScale >= 896 * 3 || screenHeight == 736 { // iPhone pro max, iPhone plus return 20 } else if screenHeight == 568 { // iPhone SE 1st gen return -10 } else { // The rest return 0 } } } ================================================ FILE: Sources/WelcomeSheet/Extensions/AnyView+Extensitons.swift ================================================ // // File.swift // // // Created by Jakub Florek on 14/01/2023. // import SwiftUI extension AnyView: Identifiable { public var id: UUID { UUID() } } ================================================ FILE: Sources/WelcomeSheet/Extensions/Color+Extensions.swift ================================================ // // Color+Extensions.swift // // // Created by Jakub Florek on 05/12/2021. // import SwiftUI extension Color { init(hex: String) { let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted) var int: UInt64 = 0 Scanner(string: hex).scanHexInt64(&int) let a, r, g, b: UInt64 switch hex.count { case 3: // RGB (12-bit) (a, r, g, b) = (255, (int >> 8) * 17, (int >> 4 & 0xF) * 17, (int & 0xF) * 17) case 6: // RGB (24-bit) (a, r, g, b) = (255, int >> 16, int >> 8 & 0xFF, int & 0xFF) case 8: // ARGB (32-bit) (a, r, g, b) = (int >> 24, int >> 16 & 0xFF, int >> 8 & 0xFF, int & 0xFF) default: (a, r, g, b) = (1, 1, 1, 0) } self.init( .sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: Double(a) / 255 ) } } ================================================ FILE: Sources/WelcomeSheet/Extensions/UIColor+Extensions.swift ================================================ // // File.swift // // // Created by Jakub Florek on 18/01/2023. // import SwiftUI extension UIColor { func toColor() -> Color { Color(self) } } ================================================ FILE: Sources/WelcomeSheet/Extensions/UIImage+Extensions.swift ================================================ // // UIImage+Extensions.swift // // // Created by Eskil Gjerde Sviggum on 30/01/2023. // import UIKit extension UIImage { func systemSymbolName() -> String? { guard let imageAsset = self.imageAsset else { return nil } let systemSymbolAssetManagerName = "CoreGlyphs" // Get the assetName, and assetManagerName. guard imageAsset.responds(to: NSSelectorFromString("assetName")), let assetName = imageAsset.value(forKey: "_assetName") as? String, imageAsset.responds(to: NSSelectorFromString("_assetManager")), let assetManager = imageAsset.value(forKey: "_assetManager") as? NSObject, let assetManagerName = assetManager.value(forKey: "_assetManagerName") as? String else { assertionFailure("assetName or assetManagerName is not available.") return nil } // Check if image is a system symbol. if assetManagerName != systemSymbolAssetManagerName { return nil } return assetName } } ================================================ FILE: Sources/WelcomeSheet/Models/UIWelcomeSheetPage.swift ================================================ // // UIWelcomeSheetPage.swift // // // Created by Eskil Gjerde Sviggum on 18/01/2023. // import UIKit @objc public class UIWelcomeSheetPage: NSObject { /// Large title displayed on the top. @IBInspectable public var title: String = "" /// Rows of content inside body. @IBOutlet public var rows: [UIWelcomeSheetPageRow] = [] /// Title for the main button. Set to `"Continue"` by @IBInspectable public var mainButtonTitle: String = "Continue" /// Color used for main buttons. When `nil`, uses default accent color. @IBInspectable public var accentColor: UIColor? /// Background color. When `nil`, uses default system background. @IBInspectable public var backgroundColor: UIColor? /// Specifies whether to show the optional button. @IBInspectable public var isShowingOptionalButton = false /// Optional button title. @IBInspectable public var optionalButtonTitle: String? /// URL to open after optional button is tapped. @IBInspectable public var optionalButtonURL: String? /// Clousure executed after optional button is tapped. public var optionalButtonAction: (() -> ())? /// Clousure executed after optional button is tapped. public var optionalButtonView: UIView? func welcomeSheetPage() -> WelcomeSheetPage { WelcomeSheetPage(title: title, rows: rows.map { $0.welcomeSheetPageRow() }, accentUIColor: accentColor, backgroundUIColor: backgroundColor, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: URL(string: optionalButtonURL ?? ""), optionalButtonAction: optionalButtonAction, optionalButtonUIView: optionalButtonView) } } ================================================ FILE: Sources/WelcomeSheet/Models/UIWelcomeSheetPageRow.swift ================================================ // // UIWelcomeSheetPageRow.swift // // // Created by Eskil Gjerde Sviggum on 18/01/2023. // import UIKit @objc public class UIWelcomeSheetPageRow: NSObject { /// Title displayed above the content. @IBInspectable public var title: String = "" /// Text displayed beneath the title. @IBInspectable public var content: String = "" /// Image displayed at the beginning of a row. @IBInspectable public var image: UIImage = UIImage() /// Color used for image. When `nil`, uses default accent color. @IBInspectable public var accentColor: UIColor? func welcomeSheetPageRow() -> WelcomeSheetPageRow { WelcomeSheetPageRow(uiImage: image, accentUIColor: accentColor, title: title, content: content) } } ================================================ FILE: Sources/WelcomeSheet/Models/WelcomeSheetPage.swift ================================================ // // WelcomeSheetPage.swift // // // Created by Jakub Florek on 27/11/2021. // import SwiftUI /// Describes Welcome Sheet page's content. public struct WelcomeSheetPage: Identifiable, Decodable { private enum CodingKeys : String, CodingKey { case title, rows, mainButtonTitle, accentColor, backgroundColor, isShowingOptionalButton, optionalButtonTitle, optionalButtonURL } public var id = UUID() /// Large title displayed on the top. public var title: String /// Rows of content inside body. public var rows: [WelcomeSheetPageRow] /// Title for the main button. Set to `"Continue"` by default. public var mainButtonTitle: String /// Color used for main buttons. When `nil`, uses default accent color. public var accentColor: Color? /// Background color. When `nil`, uses default system background. public var backgroundColor: Color? /// Specifies whether to show the optional button. public var isShowingOptionalButton = false /// Optional button title. public var optionalButtonTitle: String? /// URL to open after optional button is tapped. public var optionalButtonURL: URL? /// Clousure executed after optional button is tapped. public var optionalButtonAction: (() -> ())? /// View shown after optional button is tapped. public var optionalButtonView: AnyView? private init(title: String, rows: [WelcomeSheetPageRow], accentColor: Color? = nil, backgroundColor: Color? = nil, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonView: AnyView? = nil) { self.title = title self.rows = rows self.mainButtonTitle = mainButtonTitle ?? "Continue" self.accentColor = accentColor self.backgroundColor = backgroundColor self.isShowingOptionalButton = true self.optionalButtonTitle = optionalButtonTitle self.optionalButtonURL = optionalButtonURL self.optionalButtonAction = optionalButtonAction self.optionalButtonView = optionalButtonView } /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonUIView: UIView? = nil) { self.init(title: title, rows: rows, accentColor: nil, backgroundColor: nil, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(uiVIew: optionalButtonUIView)) } // V SwiftUI Initializers V /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], accentColor: Color?, backgroundColor: Color?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonView: (() -> any View)? = nil) { self.init(title: title, rows: rows, accentColor: accentColor, backgroundColor: backgroundColor, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(view: optionalButtonView)) } /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], accentColor: Color?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonView: (() -> any View)? = nil) { self.init(title: title, rows: rows, accentColor: accentColor, backgroundColor: nil, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(view: optionalButtonView)) } /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], backgroundColor: Color?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonView: (() -> any View)? = nil) { self.init(title: title, rows: rows, accentColor: nil, backgroundColor: backgroundColor, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(view: optionalButtonView)) } // V UIKit initializer V /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], accentUIColor: UIColor?, backgroundUIColor: UIColor?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonUIView: UIView? = nil) { self.init(title: title, rows: rows, accentColor: accentUIColor?.toColor(), backgroundColor: backgroundUIColor?.toColor(), mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(uiVIew: optionalButtonUIView)) } /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], accentUIColor: UIColor?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonUIView: UIView? = nil) { self.init(title: title, rows: rows, accentColor: accentUIColor?.toColor(), backgroundColor: nil, mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(uiVIew: optionalButtonUIView)) } /// Creates Welcome Sheet page. public init(title: String, rows: [WelcomeSheetPageRow], backgroundUIColor: UIColor?, mainButtonTitle: String? = nil, optionalButtonTitle: String? = nil, optionalButtonURL: URL? = nil, optionalButtonAction: (() -> ())? = nil, optionalButtonUIView: UIView? = nil) { self.init(title: title, rows: rows, accentColor: nil, backgroundColor: backgroundUIColor?.toColor(), mainButtonTitle: mainButtonTitle, optionalButtonTitle: optionalButtonTitle, optionalButtonURL: optionalButtonURL, optionalButtonAction: optionalButtonAction, optionalButtonView: Self.getAnyViewFrom(uiVIew: optionalButtonUIView)) } // V Codable initializer V public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) title = try container.decode(String.self, forKey: .title) rows = try container.decode([WelcomeSheetPageRow].self, forKey: .rows) do { mainButtonTitle = try container.decode(String.self, forKey: .mainButtonTitle) } catch { mainButtonTitle = "Continue" } do { let colorHex = try container.decode(String.self, forKey: .accentColor) accentColor = Color(hex: colorHex) } catch { accentColor = nil } do { let colorHex = try container.decode(String.self, forKey: .backgroundColor) backgroundColor = Color(hex: colorHex) } catch { accentColor = nil } do { optionalButtonTitle = try container.decode(String.self, forKey: .optionalButtonTitle) } catch { optionalButtonTitle = nil } do { let urlString = try container.decode(String.self, forKey: .optionalButtonURL) optionalButtonURL = URL(string: urlString) } catch { optionalButtonURL = nil } do { isShowingOptionalButton = try container.decode(Bool.self, forKey: .isShowingOptionalButton) } catch { if optionalButtonTitle != nil { isShowingOptionalButton = true } else { isShowingOptionalButton = false } } } } private extension WelcomeSheetPage { static func getAnyViewFrom(view: (() -> any View)?) -> AnyView? { guard let view else { return nil } return AnyView(view()) } static func getAnyViewFrom(uiVIew: UIView?) -> AnyView? { guard let uiVIew else { return nil } return AnyView(OptionalButtonView(uiView: uiVIew)) } } ================================================ FILE: Sources/WelcomeSheet/Models/WelcomeSheetPageRow.swift ================================================ // // WelcomeSheetPageRow.swift // // // Created by Jakub Florek on 27/11/2021. // import SwiftUI /// Describes Welcome Sheet page row's content. public struct WelcomeSheetPageRow: Identifiable, Decodable { private enum CodingKeys : String, CodingKey { case title, content, imageName, accentColor } public var id = UUID() /// Title displayed above the content. public var title: String /// Text displayed beneath the title. public var content: String /// Image displayed at the beginning of a row. public var image: Image /// Color used for image. When `nil`, uses default accent color. public var accentColor: Color? // V SwiftUI Initializers V /// Creates Welcome Sheet page row with given image, title and content. public init(image: Image, accentColor: Color? = nil, title: String, content: String) { self.image = image self.accentColor = accentColor self.title = title self.content = content } /// Creates Welcome Sheet page row with system image, given title and content. Tints image with specified colour. public init(imageSystemName: String, accentColor: Color?, title: String, content: String) { self.init(image: Image(systemName: imageSystemName), accentColor: accentColor, title: title, content: content) } /// Creates Welcome Sheet page row with image name, given title and content. Tints image with specified colour. public init(imageNamed: String, accentColor: Color?, title: String, content: String) { self.init(image: Image(imageNamed), accentColor: accentColor, title: title, content: content) } // V UIKit initializers V /// Creates Welcome Sheet page row with given image, title and content. Tints image with specified colour. public init(uiImage: UIImage, accentUIColor: UIColor? = nil, title: String, content: String) { if let systemSymbolName = uiImage.systemSymbolName() { self.init(imageSystemName: systemSymbolName, accentUIColor: accentUIColor, title: title, content: content) } else { self.init(image: Image(uiImage: uiImage), accentColor: accentUIColor?.toColor(), title: title, content: content) } } /// Creates Welcome Sheet page row with system image, given title and content. Tints image with specified colour. public init(imageSystemName: String, accentUIColor: UIColor?, title: String, content: String) { self.init(image: Image(systemName: imageSystemName), accentColor: accentUIColor?.toColor(), title: title, content: content) } /// Creates Welcome Sheet page row with image name, given title and content. Tints image with specified colour. public init(imageNamed: String, accentUIColor: UIColor?, title: String, content: String) { self.init(image: Image(imageNamed), accentColor: accentUIColor?.toColor(), title: title, content: content) } // V Universal initializers V /// Creates Welcome Sheet page row with system image, given title and content. Tints image with specified colour. public init(imageSystemName: String, title: String, content: String) { self.init(image: Image(systemName: imageSystemName), title: title, content: content) } /// Creates Welcome Sheet page row with image name, given title and content. Tints image with specified colour. public init(imageNamed: String, title: String, content: String) { self.init(image: Image(imageNamed), title: title, content: content) } // V Codable initializer V public init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) title = try container.decode(String.self, forKey: .title) content = try container.decode(String.self, forKey: .content) let imageName = try container.decode(String.self, forKey: .imageName) if let uiImage = UIImage(named: imageName) { image = Image(uiImage: uiImage) } else { image = Image(systemName: imageName) } do { let colorHex = try container.decode(String.self, forKey: .accentColor) accentColor = Color(hex: colorHex) } catch { accentColor = nil } } } ================================================ FILE: Sources/WelcomeSheet/Views/HorizontalAlignment.swift ================================================ // // File.swift // // // Created by Jakub Florek on 14/01/2023. // import SwiftUI extension HorizontalAlignment { enum MidIcons: AlignmentID { static func defaultValue(in d: ViewDimensions) -> CGFloat { d[.leading] } } static let midIcons = HorizontalAlignment(MidIcons.self) } ================================================ FILE: Sources/WelcomeSheet/Views/OptionalButtonView.swift ================================================ // // File.swift // // // Created by Jakub Florek on 18/01/2023. // import SwiftUI struct OptionalButtonView: UIViewRepresentable { let uiView: UIView func makeUIView(context: Context) -> UIView { uiView } func updateUIView(_ uiView: UIView, context: Context) {} } ================================================ FILE: Sources/WelcomeSheet/Views/ScrollOnlyOnOverflow.swift ================================================ // Source: https://stackoverflow.com/a/66875954 import SwiftUI struct OverflowScrollView: View where Content : View { @State private var axes: Axis.Set private let showsIndicator: Bool private let content: Content init(_ axes: Axis.Set = .vertical, showsIndicators: Bool = true, @ViewBuilder content: @escaping () -> Content) { self._axes = .init(wrappedValue: axes) self.showsIndicator = showsIndicators self.content = content() } fileprivate init(scrollView: ScrollView) { self._axes = .init(wrappedValue: scrollView.axes) self.showsIndicator = scrollView.showsIndicators self.content = scrollView.content } public var body: some View { GeometryReader { geometry in ScrollView(axes, showsIndicators: showsIndicator) { content .background(ContentSizeReader()) .onPreferenceChange(ContentSizeKey.self) { if $0.height <= geometry.size.height { axes.remove(.vertical) } if $0.width <= geometry.size.width { axes.remove(.horizontal) } } } } } } private struct ContentSizeReader: View { var body: some View { GeometryReader { Color.clear .preference( key: ContentSizeKey.self, value: $0.frame(in: .local).size ) } } } private struct ContentSizeKey: PreferenceKey { static var defaultValue: CGSize { .zero } static func reduce(value: inout Value, nextValue: () -> Value) { value = CGSize(width: value.width+nextValue().width, height: value.height+nextValue().height) } } extension ScrollView { func scrollOnlyOnOverflow() -> some View { OverflowScrollView(scrollView: self) } } ================================================ FILE: Sources/WelcomeSheet/Views/WelcomeSheetModal.swift ================================================ // // WelcomeSheetModal.swift // // // Created by Jakub Florek on 14/01/2023. // import SwiftUI open class ModalWelcomeSheetUIHostingController: UIHostingController, UIPopoverPresentationControllerDelegate { override internal init(rootView: WelcomeSheetView) { super.init(rootView: rootView) self.rootView.onDismiss = getOnDismiss(with: rootView.onDismiss) modalPresentationStyle = .formSheet preferredContentSize = CGSize(width: iPadSheetDimensions.width, height: iPadSheetDimensions.height) presentationController?.delegate = self } required public init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { rootView.onDismiss() } internal func getOnDismiss(with action: @escaping () -> Void) -> (() -> Void) { return { [weak self] in action() self?.dismiss(animated: true) } } } class ModalWelcomeSheetUIViewController: UIViewController { var isSlideToDismissDisabled: Bool? var welcomeSheetView: WelcomeSheetView? func show() { guard let welcomeSheetView else { return } let hostVC = ModalWelcomeSheetUIHostingController(rootView: welcomeSheetView) hostVC.overrideUserInterfaceStyle = self.overrideUserInterfaceStyle hostVC.isModalInPresentation = isSlideToDismissDisabled ?? false present(hostVC, animated: true) } } struct ModalWelcomeSheetUIViewControllerRepresentable: UIViewControllerRepresentable { let show: Bool let isSlideToDismissDisabled: Bool let preferredColorScheme: ColorScheme? let welcomeSheetView: WelcomeSheetView var userInterfaceStyle: UIUserInterfaceStyle? { if preferredColorScheme == .dark { return .dark } else { return .light } } func makeUIViewController(context: UIViewControllerRepresentableContext) -> ModalWelcomeSheetUIViewController { let vc = ModalWelcomeSheetUIViewController() vc.welcomeSheetView = welcomeSheetView vc.isSlideToDismissDisabled = isSlideToDismissDisabled if let userInterfaceStyle { vc.overrideUserInterfaceStyle = userInterfaceStyle } return vc } func updateUIViewController(_ uiViewController: ModalWelcomeSheetUIViewController, context: UIViewControllerRepresentableContext) { if show { uiViewController.show() } else { uiViewController.dismiss(animated: true) } } } ================================================ FILE: Sources/WelcomeSheet/Views/WelcomeSheetPageView.swift ================================================ // // WelcomeSheetPageView.swift // // // Created by Jakub Florek on 27/11/2021. // import SwiftUI struct WelcomeSheetPageView: View { let page: WelcomeSheetPage let restPages: [WelcomeSheetPage] let onDismiss: () -> Void let isiPad = UIDevice.current.userInterfaceIdiom == .pad @State private var optionalView: AnyView? var body: some View { VStack(spacing: 0) { ScrollView { VStack(spacing: iPhoneDimensions.spacing) { HStack { Spacer() if #available(iOS 15.0, *) { Text(page.title) .font(.largeTitle) .fontWeight(.bold) .lineSpacing(8) .multilineTextAlignment(.center) .padding(.top, iPhoneDimensions.topPadding - (isiPad ? 15 : 0)) .fixedSize(horizontal: false, vertical: true) .accessibilityHeading(.h1) } else { Text(page.title) .font(.largeTitle) .fontWeight(.bold) .lineSpacing(8) .multilineTextAlignment(.center) .padding(.top, iPhoneDimensions.topPadding - (isiPad ? 15 : 0)) .fixedSize(horizontal: false, vertical: true) } Spacer() } VStack(alignment: .midIcons, spacing: 30) { ForEach(page.rows) { row in HStack(spacing: 17.5) { row.image .renderingMode(.template) .resizable() .scaledToFit() .foregroundColor(row.accentColor ?? Color.accentColor) .frame(width: 37, height: 37) .alignmentGuide(.midIcons) { d in d[HorizontalAlignment.center] } .accessibility(hidden: true) VStack(alignment: .leading, spacing: 2) { Text(row.title) .font(.headline) .lineLimit(2) .fixedSize(horizontal: false, vertical: true) Text(row.content) .font(.subheadline) .foregroundColor(.secondary) .fixedSize(horizontal: false, vertical: true) } Spacer() } .padding(.horizontal, 20 + iPhoneDimensions.horizontalPaddingAddend) .accessibilityElement(children: .combine) } } } .padding(.horizontal) .padding(.horizontal, isiPad ? 45 : 0) } .scrollOnlyOnOverflow() VStack(spacing: 5) { if page.isShowingOptionalButton { if let optionalButtonTitle = page.optionalButtonTitle { Button(optionalButtonTitle) { if let view = page.optionalButtonView { optionalView = view } else if let action = page.optionalButtonAction { action() } else if let url = page.optionalButtonURL { UIApplication.shared.open(url) } } .buttonStyle(PlainButtonStyle()) .font(Font.headline.weight(.medium)) .foregroundColor(page.accentColor ?? Color.accentColor) .padding(.top) } } if let nextPage = restPages.first { NavigationLink { WelcomeSheetPageView(page: nextPage, restPages: restPages.filter({ $0.id != nextPage.id }), onDismiss: onDismiss) } label: { ZStack { page.accentColor ?? Color.accentColor Text(page.mainButtonTitle) .font(.headline) .foregroundColor(.white) .padding() } .frame(width: isiPad ? iPadSheetDimensions.width / 1.7 : nil) .fixedSize(horizontal: false, vertical: true) .clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous)) } .buttonStyle(PlainButtonStyle()) .padding(.horizontal, 10) .padding(.top) } else { Button { onDismiss() } label: { ZStack { page.accentColor ?? Color.accentColor Text(page.mainButtonTitle) .font(.headline) .foregroundColor(.white) .padding() } .frame(width: isiPad ? iPadSheetDimensions.width / 1.7 : nil) .fixedSize(horizontal: false, vertical: true) .clipShape(RoundedRectangle(cornerRadius: 15, style: .continuous)) } .buttonStyle(PlainButtonStyle()) .padding(.horizontal, 10) .padding(.top) } } .padding(.horizontal, 15 + iPhoneDimensions.horizontalPaddingAddend) .padding(.bottom, 60) .sheet(item: $optionalView) { view in view.edgesIgnoringSafeArea(.all) } } .background( page.backgroundColor.edgesIgnoringSafeArea(.all) ) .edgesIgnoringSafeArea(.top) } } ================================================ FILE: Sources/WelcomeSheet/Views/WelcomeSheetView.swift ================================================ // // WelcomeSheetView.swift // // // Created by Jakub Florek on 27/11/2021. // import SwiftUI public struct WelcomeSheetView: View { var pages: [WelcomeSheetPage] var onDismiss: () -> Void public var body: some View { NavigationView { if let firstPage = pages.first { WelcomeSheetPageView(page: firstPage, restPages: pages.filter({ $0.id != firstPage.id }), onDismiss: onDismiss) .navigationBarTitle(Text(""), displayMode: .inline) .navigationBarHidden(true) } } .navigationViewStyle(StackNavigationViewStyle()) } } ================================================ FILE: Sources/WelcomeSheet/WelcomeSheet.swift ================================================ // // WelcomeSheet.swift // // // Created by Jakub Florek on 27/11/2021. // import SwiftUI struct WelcomeSheet: ViewModifier { @Binding var showSheet: Bool let pages: [WelcomeSheetPage] let onDismiss: () -> Void let isSlideToDismissDisabled: Bool let preferredColorScheme: ColorScheme? func body(content: Content) -> some View { content .background(ModalWelcomeSheetUIViewControllerRepresentable(show: showSheet, isSlideToDismissDisabled: isSlideToDismissDisabled, preferredColorScheme: preferredColorScheme, welcomeSheetView: WelcomeSheetView(pages: pages, onDismiss: getOnDismiss()))) } func getOnDismiss() -> () -> Void { return { showSheet = false onDismiss() } } } public extension View { /// Presents Welcome Sheet with given pages when a binding to a Boolean value that you provide is true. func welcomeSheet(isPresented showSheet: Binding, onDismiss: @escaping () -> Void = {}, isSlideToDismissDisabled: Bool = false, preferredColorScheme: ColorScheme? = nil, pages: [WelcomeSheetPage]) -> some View { modifier(WelcomeSheet(showSheet: showSheet, pages: pages, onDismiss: onDismiss, isSlideToDismissDisabled: isSlideToDismissDisabled, preferredColorScheme: preferredColorScheme)) } } ================================================ FILE: Sources/WelcomeSheet/WelcomeSheetController.swift ================================================ // // WelcomeSheetController.swift // // // Created by Kevin Romero Peces-Barba on 2/10/22. // import UIKit open class WelcomeSheetController: ModalWelcomeSheetUIHostingController { /// Pages of the sheet. public var pages: [WelcomeSheetPage] = [] { didSet { rootView.pages = pages } } /// Closure called on dismissal of the sheet. public var onDismiss: (() -> Void)? /// Creates Welcome Sheet controller without pages and onDismiss action. public init() { super.init(rootView: WelcomeSheetView(pages: [], onDismiss: {})) rootView.onDismiss = getOnDismiss(with: didDismiss) } /// Creates Welcome Sheet controller with given pages and onDismiss action. public init(pages: [WelcomeSheetPage], isSlideToDismissDisabled: Bool = false, onDismiss: @escaping () -> Void = {}) { super.init(rootView: WelcomeSheetView(pages: pages, onDismiss: {})) self.onDismiss = onDismiss rootView.onDismiss = getOnDismiss(with: didDismiss) self.pages = pages self.isModalInPresentation = isSlideToDismissDisabled } required public init?(coder: NSCoder) { super.init(rootView: WelcomeSheetView(pages: [], onDismiss: {})) rootView.onDismiss = getOnDismiss(with: didDismiss) } open func didDismiss() { self.onDismiss?() } } ================================================ FILE: Sources/WelcomeSheet/WelcomeSheetStoryboardController.swift ================================================ // // WelcomeSheetController.swift // // // Created by Eskil Gjerde Sviggum on 29/01/2023. // import UIKit import SwiftUI @objc public protocol WelcomeSheetDelegate: AnyObject { @objc optional func welcomeSheetController(didDismiss welcomeSheetController: UIViewController) @objc optional func welcomeSheetController(pages welcomeSheetController: UIViewController) -> [UIWelcomeSheetPage] } open class WelcomeSheetStoryboardController: ModalWelcomeSheetUIHostingController { @IBOutlet weak public var delegate: WelcomeSheetDelegate? /// Pages of the sheet. @IBOutlet public var pages: [UIWelcomeSheetPage] = [] { didSet { rootView.pages = pages.map { $0.welcomeSheetPage() } } } /// Closure called on dismissal of the sheet. public var onDismiss: (() -> Void)? /// Creates Welcome Sheet controller without pages and onDismiss action. public init() { super.init(rootView: WelcomeSheetView(pages: [], onDismiss: {})) rootView.onDismiss = getOnDismiss(with: didDismiss) } /// Creates Welcome Sheet controller with given pages and onDismiss action. public init(pages: [UIWelcomeSheetPage], isSlideToDismissDisabled: Bool = false, onDismiss: @escaping () -> Void = {}) { super.init(rootView: WelcomeSheetView(pages: pages.map { $0.welcomeSheetPage() }, onDismiss: {})) self.onDismiss = onDismiss rootView.onDismiss = getOnDismiss(with: didDismiss) self.pages = pages self.isModalInPresentation = isSlideToDismissDisabled } required public init?(coder: NSCoder) { super.init(rootView: WelcomeSheetView(pages: [], onDismiss: {})) rootView.onDismiss = getOnDismiss(with: didDismiss) } public override func viewDidLoad() { if let pages = delegate?.welcomeSheetController?(pages: self) { self.pages = pages } else { rootView.pages = pages.map { $0.welcomeSheetPage() } } } open func didDismiss() { delegate?.welcomeSheetController?(didDismiss: self) self.onDismiss?() } }