├── Demo ├── vince.jpg ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── ipad76.png │ │ ├── mac128.png │ │ ├── mac16.png │ │ ├── mac256.png │ │ ├── mac32.png │ │ ├── mac512.png │ │ ├── mac64.png │ │ ├── ipad152.png │ │ ├── iphone120.png │ │ ├── iphone180.png │ │ ├── mac1024.png │ │ ├── ipadPro167.png │ │ ├── settings58.png │ │ ├── settings87.png │ │ ├── spotlight80.png │ │ ├── appstore1024.png │ │ ├── ipadSettings29.png │ │ ├── ipadSettings58.png │ │ ├── notification40.png │ │ ├── notification60.png │ │ ├── spotlight120.png │ │ ├── ipadSpotlight40.png │ │ ├── ipadSpotlight80.png │ │ ├── ipadNotification20.png │ │ └── ipadNotification40.png │ ├── AppIcon.solidimagestack │ │ ├── Back.solidimagestacklayer │ │ │ ├── Contents.json │ │ │ └── Content.imageset │ │ │ │ ├── or.jpg │ │ │ │ └── Contents.json │ │ ├── Front.solidimagestacklayer │ │ │ ├── Contents.json │ │ │ └── Content.imageset │ │ │ │ ├── galss.png │ │ │ │ └── Contents.json │ │ ├── Middle.solidimagestacklayer │ │ │ ├── Contents.json │ │ │ └── Content.imageset │ │ │ │ ├── dash circle.png │ │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Brand Assets.brandassets │ │ ├── App Icon.imagestack │ │ │ ├── Back.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ ├── Front.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ ├── Middle.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── App Icon - App Store.imagestack │ │ │ ├── Back.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ ├── Front.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ ├── Middle.imagestacklayer │ │ │ │ ├── Contents.json │ │ │ │ └── Content.imageset │ │ │ │ │ └── Contents.json │ │ │ └── Contents.json │ │ ├── Top Shelf Image.imageset │ │ │ └── Contents.json │ │ ├── Top Shelf Image Wide.imageset │ │ │ └── Contents.json │ │ └── Contents.json │ └── AccentColor.colorset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── Localizable.xcstrings ├── TestView.swift ├── TestAPNS │ ├── video.apns │ ├── images.apns │ ├── rating.apns │ ├── watchVideo.apns │ └── watchVideo copy.apns ├── Demo.entitlements ├── Info.plist └── DemoApp.swift ├── Action ├── Media.xcassets │ ├── Contents.json │ └── TouchBarBezel.colorset │ │ └── Contents.json └── Info.plist ├── AppClips ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── mac16.png │ │ ├── mac32.png │ │ ├── mac64.png │ │ ├── ipad152.png │ │ ├── ipad76.png │ │ ├── mac1024.png │ │ ├── mac128.png │ │ ├── mac256.png │ │ ├── mac512.png │ │ ├── ipadPro167.png │ │ ├── iphone120.png │ │ ├── iphone180.png │ │ ├── settings58.png │ │ ├── settings87.png │ │ ├── appstore1024.png │ │ ├── spotlight120.png │ │ ├── spotlight80.png │ │ ├── ipadSettings29.png │ │ ├── ipadSettings58.png │ │ ├── ipadSpotlight40.png │ │ ├── ipadSpotlight80.png │ │ ├── notification40.png │ │ ├── notification60.png │ │ ├── ipadNotification20.png │ │ └── ipadNotification40.png │ └── AccentColor.colorset │ │ └── Contents.json ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── AppClips.entitlements ├── Info.plist └── AppClipsApp.swift ├── iMessage ├── Assets.xcassets │ ├── Contents.json │ ├── vince.imageset │ │ ├── vince.jpg │ │ └── Contents.json │ └── iMessage App Icon.stickersiconset │ │ ├── icon-messages-app-27x20@2x.png │ │ ├── icon-messages-app-27x20@3x.png │ │ ├── icon-messages-app-store-1024x768.png │ │ ├── icon-messages-settings-29x29@2x.png │ │ ├── icon-messages-settings-29x29@3x.png │ │ ├── icon-messages-app-iPadAir-67x50@2x.png │ │ ├── icon-messages-app-iPadAir-74x55@2x.png │ │ ├── icon-messages-app-iPhone-60x45@2x.png │ │ ├── icon-messages-app-iPhone-60x45@3x.png │ │ ├── icon-messages-app-store-1024x1024.png │ │ ├── icon-messages-settings-29x29@2x 1.png │ │ ├── icon-messages-transcript-32x24@2x.png │ │ ├── icon-messages-transcript-32x24@3x.png │ │ └── Contents.json └── Info.plist ├── Notification ├── Resources │ ├── heroes-1.jpg │ ├── heroes-2.jpg │ ├── heroes-3.jpg │ └── highlights.mp4 ├── Info.plist ├── NotificationViewController.swift └── NotificationViewController+UserNotifications.swift ├── HeroesWatch Watch App ├── Assets.xcassets │ ├── Contents.json │ ├── AppIcon.appiconset │ │ ├── ItunesArtwork@2x.png │ │ └── Contents.json │ └── AccentColor.colorset │ │ └── Contents.json ├── highlights.mp4 ├── Preview Content │ └── Preview Assets.xcassets │ │ └── Contents.json ├── HeroesWatch Watch App.entitlements ├── ContentView.swift └── HeroesWatchApp.swift ├── Heroes ├── Sources │ ├── HeroShared │ │ ├── Resources │ │ │ ├── Assets.xcassets │ │ │ │ ├── Contents.json │ │ │ │ ├── pol.imageset │ │ │ │ │ ├── pol.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── alex.imageset │ │ │ │ │ ├── alex.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── brad.imageset │ │ │ │ │ ├── brad.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── jane.imageset │ │ │ │ │ ├── jane.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── mete.imageset │ │ │ │ │ ├── mete.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── sara.imageset │ │ │ │ │ ├── sara.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── shai.imageset │ │ │ │ │ ├── shai.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── zach.imageset │ │ │ │ │ ├── zach.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── andrea.imageset │ │ │ │ │ ├── andrea.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── andrei.imageset │ │ │ │ │ ├── andrei.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── beyza.imageset │ │ │ │ │ ├── beyza.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── davide.imageset │ │ │ │ │ ├── davide.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── emilio.imageset │ │ │ │ │ ├── emilio.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── flora.imageset │ │ │ │ │ ├── flora.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── gyuree.imageset │ │ │ │ │ ├── gyuree.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios4.imageset │ │ │ │ │ ├── images.jpeg │ │ │ │ │ └── Contents.json │ │ │ │ ├── josip.imageset │ │ │ │ │ ├── josip.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── lukasz.imageset │ │ │ │ │ ├── lukasz.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── marcin.imageset │ │ │ │ │ ├── marcin.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── marco.imageset │ │ │ │ │ ├── marco.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── natan.imageset │ │ │ │ │ ├── natan.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── pedro.imageset │ │ │ │ │ ├── pedro.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── peter.imageset │ │ │ │ │ ├── peter.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── pietro.imageset │ │ │ │ │ ├── pietro.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── vince 1.imageset │ │ │ │ │ ├── vince.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── vince.imageset │ │ │ │ │ ├── vince.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── alberto.imageset │ │ │ │ │ ├── alberto.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── batuhan.imageset │ │ │ │ │ ├── batuhan.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── borbala.imageset │ │ │ │ │ ├── borbala.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── davide2.imageset │ │ │ │ │ ├── davide2.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios8.imageset │ │ │ │ │ ├── IOS_8_logo.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios9.imageset │ │ │ │ │ ├── IOS_9_Logo.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── michael.imageset │ │ │ │ │ ├── michael.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── pradnya.imageset │ │ │ │ │ ├── pradnya.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── stefano.imageset │ │ │ │ │ ├── stefano.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── Krysztof.imageset │ │ │ │ │ ├── Krysztof.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios14.imageset │ │ │ │ │ ├── IOS_14_Logo.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── vincenzo.imageset │ │ │ │ │ ├── vincenzo.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── libranner.imageset │ │ │ │ │ ├── libranner.jpg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios3.imageset │ │ │ │ │ ├── IPhone_OS_3_logo.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── logo.imageset │ │ │ │ │ ├── swift_heroes_logo.jpeg │ │ │ │ │ └── Contents.json │ │ │ │ ├── ios10.imageset │ │ │ │ │ ├── 240px-IOS_10_logo.svg.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── wordLogo.imageset │ │ │ │ │ ├── logo_swiftheroes_ufficiale_SH-blu.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── heroBlue.colorset │ │ │ │ │ └── Contents.json │ │ │ │ └── heroOrange.colorset │ │ │ │ │ └── Contents.json │ │ │ └── Localizable.xcstrings │ │ ├── Heroes.swift │ │ ├── Enums │ │ │ ├── ListType.swift │ │ │ └── OperatingSystem.swift │ │ ├── Extensions │ │ │ ├── Color+Extensions.swift │ │ │ ├── String+Extensions.swift │ │ │ └── Image+Extensions.swift │ │ ├── Protocols │ │ │ └── Listable.swift │ │ ├── Data │ │ │ ├── ListItem.swift │ │ │ └── ExtensionItem.swift │ │ ├── Spotlight │ │ │ └── Spotlight.swift │ │ └── Notifications │ │ │ └── NotificationHelper.swift │ ├── MacroClient │ │ └── main.swift │ ├── MacroMacros │ │ ├── CompilerPlugin.swift │ │ ├── DebugListMacro.swift │ │ ├── LogPropertyMacro.swift │ │ ├── NavigationTitleMacro.swift │ │ └── DebugPrintMacro.swift │ ├── HeroiOS │ │ ├── Extensions │ │ │ ├── List+Extensions.swift │ │ │ ├── UIViewController+Extensions.swift │ │ │ └── View+Extensions.swift │ │ ├── SceneDelegate.swift │ │ ├── Modifiers │ │ │ ├── ExternalScreenToolBarModifier.swift │ │ │ ├── ForegroundViewModifier.swift │ │ │ └── ExternalScreenViewModifier.swift │ │ ├── ExternalScreens │ │ │ ├── ScreenManager.swift │ │ │ ├── ExternalScreenToolBar.swift │ │ │ ├── ExternalScreenView.swift │ │ │ └── ExternalScreenControlView.swift │ │ ├── Views │ │ │ ├── BackgroundView.swift │ │ │ ├── PreviewItemView.swift │ │ │ ├── MessageView.swift │ │ │ ├── ShareView.swift │ │ │ ├── SpeakerListView.swift │ │ │ └── ExtensionListView.swift │ │ ├── Resources │ │ │ └── Localizable.xcstrings │ │ ├── AppDelegate+QuickActions.swift │ │ ├── QuickActions │ │ │ └── QuickActionsManager.swift │ │ ├── AppDelegate+Notifications.swift │ │ └── AppDelegate.swift │ └── Macros │ │ └── Macros.swift ├── .gitignore ├── test.apns ├── Tests │ ├── HeroiOSTests │ │ └── HeroiOSTests.swift │ ├── HeroSharedTests │ │ └── HeroSharedTests.swift │ └── MacroTests │ │ └── MacroTests.swift └── Package.swift ├── SwiftHeroesFaq ├── en │ └── SwiftHeroesFaq.json └── it │ └── SwiftHeroesFaq.json ├── Demo.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── vince.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ └── swiftpm │ │ └── Package.resolved ├── xcuserdata │ ├── u380112.xcuserdatad │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ └── vince.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── xcshareddata │ └── xcschemes │ ├── Demo.xcscheme │ ├── Action.xcscheme │ ├── iMessage.xcscheme │ ├── Spotlight.xcscheme │ ├── Notification.xcscheme │ ├── NotificationService.xcscheme │ └── Share.xcscheme ├── Spotlight ├── ImportExtension.swift └── Info.plist ├── NotificationService └── Info.plist ├── Preview ├── Info.plist └── PreviewViewController.swift ├── Share ├── Info.plist └── ShareViewController.swift └── README.md /Demo/vince.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/vince.jpg -------------------------------------------------------------------------------- /Action/Media.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Notification/Resources/heroes-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Notification/Resources/heroes-1.jpg -------------------------------------------------------------------------------- /Notification/Resources/heroes-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Notification/Resources/heroes-2.jpg -------------------------------------------------------------------------------- /Notification/Resources/heroes-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Notification/Resources/heroes-3.jpg -------------------------------------------------------------------------------- /HeroesWatch Watch App/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /HeroesWatch Watch App/highlights.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/HeroesWatch Watch App/highlights.mp4 -------------------------------------------------------------------------------- /Notification/Resources/highlights.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Notification/Resources/highlights.mp4 -------------------------------------------------------------------------------- /Demo/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppClips/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Localizable.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | 5 | }, 6 | "version" : "1.0" 7 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipad76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipad76.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac128.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac16.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac256.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac32.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac512.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac64.png -------------------------------------------------------------------------------- /HeroesWatch Watch App/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/vince.imageset/vince.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/vince.imageset/vince.jpg -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac16.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac32.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac64.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipad152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipad152.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/iphone120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/iphone120.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/iphone180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/iphone180.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/mac1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/mac1024.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipad152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipad152.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipad76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipad76.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac1024.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac128.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac256.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/mac512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/mac512.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadPro167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadPro167.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/settings58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/settings58.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/settings87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/settings87.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/spotlight80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/spotlight80.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadPro167.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadPro167.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/iphone120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/iphone120.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/iphone180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/iphone180.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/settings58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/settings58.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/settings87.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/settings87.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/appstore1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/appstore1024.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/notification40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/notification40.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/notification60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/notification60.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/spotlight120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/spotlight120.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/appstore1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/appstore1024.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/spotlight120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/spotlight120.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/spotlight80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/spotlight80.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadSettings29.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadSettings58.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadSpotlight40.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadSpotlight80.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/notification40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/notification40.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/notification60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/notification60.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Heroes.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import SwiftUI 3 | 4 | public class Heroes { 5 | public init() {} 6 | public var test: String = "Testing" 7 | } 8 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadNotification20.png -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/AppClips/Assets.xcassets/AppIcon.appiconset/ipadNotification40.png -------------------------------------------------------------------------------- /Demo/Localizable.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "Cool" : { 5 | 6 | }, 7 | "Name" : { 8 | 9 | } 10 | }, 11 | "version" : "1.0" 12 | } -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Heroes/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | /.build 3 | /Packages 4 | xcuserdata/ 5 | DerivedData/ 6 | .swiftpm/configuration/registries.json 7 | .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata 8 | .netrc 9 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pol.imageset/pol.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/pol.imageset/pol.jpg -------------------------------------------------------------------------------- /Heroes/Sources/MacroClient/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import Macros 9 | 10 | let a = 17 11 | let b = 25 12 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/alex.imageset/alex.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/alex.imageset/alex.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/brad.imageset/brad.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/brad.imageset/brad.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/jane.imageset/jane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/jane.imageset/jane.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/mete.imageset/mete.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/mete.imageset/mete.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/sara.imageset/sara.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/sara.imageset/sara.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/shai.imageset/shai.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/shai.imageset/shai.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/zach.imageset/zach.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/zach.imageset/zach.jpg -------------------------------------------------------------------------------- /SwiftHeroesFaq/en/SwiftHeroesFaq.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "answer" : "wow this is cool", 4 | "level" : 1, 5 | "sortOrder" : 1, 6 | "question" : "Testing Out", 7 | "linkType" : "none" 8 | } 9 | ] -------------------------------------------------------------------------------- /SwiftHeroesFaq/it/SwiftHeroesFaq.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "answer" : "wow this is cool", 4 | "level" : 1, 5 | "sortOrder" : 1, 6 | "question" : "Testing Out", 7 | "linkType" : "none" 8 | } 9 | ] -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrea.imageset/andrea.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrea.imageset/andrea.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrei.imageset/andrei.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrei.imageset/andrei.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/beyza.imageset/beyza.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/beyza.imageset/beyza.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide.imageset/davide.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide.imageset/davide.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/emilio.imageset/emilio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/emilio.imageset/emilio.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/flora.imageset/flora.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/flora.imageset/flora.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/gyuree.imageset/gyuree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/gyuree.imageset/gyuree.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios4.imageset/images.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios4.imageset/images.jpeg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/josip.imageset/josip.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/josip.imageset/josip.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/lukasz.imageset/lukasz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/lukasz.imageset/lukasz.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/marcin.imageset/marcin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/marcin.imageset/marcin.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/marco.imageset/marco.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/marco.imageset/marco.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/natan.imageset/natan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/natan.imageset/natan.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pedro.imageset/pedro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/pedro.imageset/pedro.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/peter.imageset/peter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/peter.imageset/peter.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pietro.imageset/pietro.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/pietro.imageset/pietro.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince 1.imageset/vince.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince 1.imageset/vince.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince.imageset/vince.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince.imageset/vince.jpg -------------------------------------------------------------------------------- /HeroesWatch Watch App/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/HeroesWatch Watch App/Assets.xcassets/AppIcon.appiconset/ItunesArtwork@2x.png -------------------------------------------------------------------------------- /Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/alberto.imageset/alberto.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/alberto.imageset/alberto.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/batuhan.imageset/batuhan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/batuhan.imageset/batuhan.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/borbala.imageset/borbala.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/borbala.imageset/borbala.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide2.imageset/davide2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide2.imageset/davide2.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios8.imageset/IOS_8_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios8.imageset/IOS_8_logo.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios9.imageset/IOS_9_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios9.imageset/IOS_9_Logo.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/michael.imageset/michael.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/michael.imageset/michael.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pradnya.imageset/pradnya.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/pradnya.imageset/pradnya.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/stefano.imageset/stefano.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/stefano.imageset/stefano.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/Krysztof.imageset/Krysztof.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/Krysztof.imageset/Krysztof.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios14.imageset/IOS_14_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios14.imageset/IOS_14_Logo.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vincenzo.imageset/vincenzo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/vincenzo.imageset/vincenzo.jpg -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/libranner.imageset/libranner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/libranner.imageset/libranner.jpg -------------------------------------------------------------------------------- /AppClips/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios3.imageset/IPhone_OS_3_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios3.imageset/IPhone_OS_3_logo.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/logo.imageset/swift_heroes_logo.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/logo.imageset/swift_heroes_logo.jpeg -------------------------------------------------------------------------------- /Heroes/Sources/MacroMacros/CompilerPlugin.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CompilerPlugin.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import SwiftCompilerPlugin 9 | import SwiftSyntaxMacros 10 | 11 | 12 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-27x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-27x20@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-27x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-27x20@3x.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios10.imageset/240px-IOS_10_logo.svg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios10.imageset/240px-IOS_10_logo.svg.png -------------------------------------------------------------------------------- /Demo.xcodeproj/project.xcworkspace/xcuserdata/vince.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo.xcodeproj/project.xcworkspace/xcuserdata/vince.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/or.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/or.jpg -------------------------------------------------------------------------------- /HeroesWatch Watch App/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-store-1024x768.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-store-1024x768.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@3x.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/galss.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/galss.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPadAir-67x50@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPadAir-67x50@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPadAir-74x55@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPadAir-74x55@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPhone-60x45@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPhone-60x45@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPhone-60x45@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-iPhone-60x45@3x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-store-1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-app-store-1024x1024.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@2x 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-settings-29x29@2x 1.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-transcript-32x24@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-transcript-32x24@2x.png -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-transcript-32x24@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/icon-messages-transcript-32x24@3x.png -------------------------------------------------------------------------------- /Demo/TestView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TestView.swift 3 | // Demo 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import SwiftUI 9 | import Macros 10 | 11 | 12 | @NavigationTitle("Cool") 13 | struct UserProfileView: View { 14 | 15 | } 16 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/dash circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Demo/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/dash circle.png -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/wordLogo.imageset/logo_swiftheroes_ufficiale_SH-blu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vinced45/Swift-Heroes-Demo/HEAD/Heroes/Sources/HeroShared/Resources/Assets.xcassets/wordLogo.imageset/logo_swiftheroes_ufficiale_SH-blu.png -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Demo/TestAPNS/video.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "category" : "video", 4 | "alert": { 5 | "title": "Swift Heroes Push", 6 | "body": "Open this to see our cool video" 7 | } 8 | }, 9 | "Simulator Target Bundle": "com.swiftheroes.Demo" 10 | } 11 | -------------------------------------------------------------------------------- /Action/Media.xcassets/TouchBarBezel.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | }, 6 | "colors" : [ 7 | { 8 | "idiom" : "mac", 9 | "color" : { 10 | "reference" : "systemPurpleColor" 11 | } 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /Demo/TestAPNS/images.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "category" : "images", 4 | "alert": { 5 | "title": "Swift Heroes Slideshow", 6 | "body": "This is an example of a slideshow" 7 | } 8 | }, 9 | "Simulator Target Bundle": "com.swiftheroes.Demo" 10 | } 11 | -------------------------------------------------------------------------------- /Demo/TestAPNS/rating.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "category" : "default", 4 | "alert": { 5 | "title": "Swift Heroes Ratings", 6 | "body": "Please rate us to tell us how we did." 7 | } 8 | }, 9 | "Simulator Target Bundle": "com.swiftheroes.Demo" 10 | } 11 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Enums/ListType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum ListType: String { 11 | case sectionHeader 12 | case speaker 13 | case extensionItem 14 | case faq 15 | } 16 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Back.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "or.jpg", 5 | "idiom" : "vision", 6 | "scale" : "2x" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /HeroesWatch Watch App/HeroesWatch Watch App.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Front.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "galss.png", 5 | "idiom" : "vision", 6 | "scale" : "2x" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Heroes/test.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "alert": { 4 | "title": "Cool Video", 5 | "body": "You can do video on Apple Watch!" 6 | }, 7 | "category": "video", 8 | "thread-id": "5280" 9 | }, 10 | "Simulator Target Bundle": "com.swiftheroes.Demo.watchkitapp" 11 | } 12 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Middle.solidimagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "dash circle.png", 5 | "idiom" : "vision", 6 | "scale" : "2x" 7 | } 8 | ], 9 | "info" : { 10 | "author" : "xcode", 11 | "version" : 1 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/Top Shelf Image.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Extensions/Color+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Color.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | public extension Color { 11 | static let heroOrange = Color("heroOrange", bundle: .module) 12 | static let heroBlue = Color("heroBlue", bundle: .module) 13 | } 14 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/Top Shelf Image Wide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /HeroesWatch Watch App/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "ItunesArtwork@2x.png", 5 | "idiom" : "universal", 6 | "platform" : "watchos", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Back.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Front.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "tv", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "tv", 9 | "scale" : "2x" 10 | } 11 | ], 12 | "info" : { 13 | "author" : "xcode", 14 | "version" : 1 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/AppIcon.solidimagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.solidimagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.solidimagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.solidimagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.imagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.imagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.imagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /Demo/TestAPNS/watchVideo.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "alert": { 4 | "title": "Silver Salmon Creek", 5 | "body": "You are within 5 miles of Silver Salmon Creek." 6 | }, 7 | "category": "LandmarkNear", 8 | "thread-id": "5280" 9 | }, 10 | "landmarkIndex": 1, 11 | "Simulator Target Bundle": "com.swiftheroes.Demo.watchkitapp" 12 | } 13 | 14 | -------------------------------------------------------------------------------- /AppClips/AppClips.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.developer.parent-application-identifiers 6 | 7 | $(AppIdentifierPrefix)com.swiftheroes.Demo 8 | 9 | 10 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/App Icon - App Store.imagestack/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | }, 6 | "layers" : [ 7 | { 8 | "filename" : "Front.imagestacklayer" 9 | }, 10 | { 11 | "filename" : "Middle.imagestacklayer" 12 | }, 13 | { 14 | "filename" : "Back.imagestacklayer" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /AppClips/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSAppClip 6 | 7 | NSAppClipRequestEphemeralUserNotification 8 | 9 | NSAppClipRequestLocationConfirmation 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Extensions/List+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | public extension List { 11 | func customListStyle() -> some View { 12 | self 13 | #if os(iOS) 14 | .listStyle(.grouped) 15 | #elseif os(macOS) 16 | .listStyle(.sidebar) 17 | #endif 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Extensions/String+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // String.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import Foundation 9 | 10 | public extension String { 11 | static let iphone = "iphone" 12 | static let watch = "applewatch" 13 | static let ipad = "ipad" 14 | static let mac = "macbook" 15 | static let tv = "appletv" 16 | static let xr = "visionpro" 17 | } 18 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Protocols/Listable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Listable.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | public protocol Listable { 12 | var id: String { get } 13 | var title: String { get } 14 | var subtitle: String { get } 15 | var image: Image { get } 16 | var badges: [String] { get } 17 | var type: ListType { get } 18 | } 19 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/vince.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "vince.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Demo/TestAPNS/watchVideo copy.apns: -------------------------------------------------------------------------------- 1 | { 2 | "aps": { 3 | "category" : "default", 4 | "alert": { 5 | "title": "Beautiful View", 6 | "subtitle": "", 7 | "body" : "Denali, Alaska", 8 | }, 9 | "mutable-content": 1 10 | }, 11 | "attachment-url": "https://www.nps.gov/dena/learn/nature/images/wildlife-landing.jpg", 12 | "Simulator Target Bundle": "com.swiftheroes.Demo" 13 | } 14 | -------------------------------------------------------------------------------- /Heroes/Tests/HeroiOSTests/HeroiOSTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import HeroiOS 3 | 4 | final class HeroiOSTests: XCTestCase { 5 | func testExample() throws { 6 | // XCTest Documentation 7 | // https://developer.apple.com/documentation/xctest 8 | 9 | // Defining Test Cases and Test Methods 10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Heroes/Tests/HeroSharedTests/HeroSharedTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import HeroShared 3 | 4 | final class HeroSharedTests: XCTestCase { 5 | func testExample() throws { 6 | // XCTest Documentation 7 | // https://developer.apple.com/documentation/xctest 8 | 9 | // Defining Test Cases and Test Methods 10 | // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/alex.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "alex.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/brad.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "brad.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/jane.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "jane.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/mete.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "mete.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pol.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "pol.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/sara.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "sara.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/shai.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "shai.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/zach.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "zach.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/alberto.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "alberto.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrea.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "andrea.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/andrei.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "andrei.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/batuhan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "batuhan.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/beyza.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "beyza.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/borbala.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "borbala.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "davide.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/davide2.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "davide2.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/emilio.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "emilio.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/flora.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "flora.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/gyuree.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "gyuree.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios4.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "images.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios8.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IOS_8_logo.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios9.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IOS_9_Logo.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/josip.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "josip.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/lukasz.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "lukasz.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/marcin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "marcin.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/marco.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "marco.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/michael.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "michael.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/natan.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "natan.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pedro.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "pedro.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/peter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "peter.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pietro.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "pietro.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/pradnya.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "pradnya.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/stefano.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "stefano.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince 1.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "vince.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vince.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "vince.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/Krysztof.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "Krysztof.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios14.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IOS_14_Logo.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/libranner.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "libranner.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/vincenzo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "vincenzo.jpg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Spotlight/ImportExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ImportExtension.swift 3 | // Spotlight 4 | // 5 | // Created by Vince Davis on 4/7/24. 6 | // 7 | 8 | import CoreSpotlight 9 | 10 | class ImportExtension: CSImportExtension { 11 | 12 | override func update(_ attributes: CSSearchableItemAttributeSet, forFileAt: URL) throws { 13 | // Add attributes that describe the file at contentURL. 14 | // Throw an error with details on failure. 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios3.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "IPhone_OS_3_logo.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/logo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "swift_heroes_logo.jpeg", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/ios10.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "240px-IOS_10_logo.svg.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /iMessage/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.message-payload-provider 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).MessagesViewController 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /AppClips/AppClipsApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppClipsApp.swift 3 | // AppClips 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import SwiftUI 9 | import Observation 10 | import HeroiOS 11 | import HeroShared 12 | 13 | @main 14 | struct AppClipsApp: App { 15 | @State var screenManager = ScreenManager() 16 | 17 | var body: some Scene { 18 | WindowGroup { 19 | SpeakerListView() 20 | .environment(screenManager) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/wordLogo.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "logo_swiftheroes_ufficiale_SH-blu.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /NotificationService/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionPointIdentifier 8 | com.apple.usernotifications.service 9 | NSExtensionPrincipalClass 10 | $(PRODUCT_MODULE_NAME).NotificationService 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Demo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "originHash" : "17764b17a716c53bb44bc8b2eb5cca990ca86802f763a445d883f1bbc6ad8c0d", 3 | "pins" : [ 4 | { 5 | "identity" : "swift-syntax", 6 | "kind" : "remoteSourceControl", 7 | "location" : "https://github.com/swiftlang/swift-syntax.git", 8 | "state" : { 9 | "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", 10 | "version" : "509.1.1" 11 | } 12 | } 13 | ], 14 | "version" : 3 15 | } 16 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SceneDelegate.swift 3 | // Demo 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | #if os(iOS) 9 | import UIKit 10 | public class SceneDelegate: UIResponder, UIWindowSceneDelegate { 11 | public func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void) { 12 | QuickActionsManager.shared.handleQaItem(type: shortcutItem.type) 13 | print("scene delegate with item \(shortcutItem.type)") 14 | } 15 | } 16 | #endif 17 | -------------------------------------------------------------------------------- /Heroes/Sources/MacroMacros/DebugListMacro.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DebugListMacro.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import SwiftCompilerPlugin 9 | import SwiftSyntax 10 | import SwiftSyntaxBuilder 11 | import SwiftSyntaxMacros 12 | 13 | //public struct DebugListMacro: MemberMacro { 14 | // public static func expansion( 15 | // of node: AttributeSyntax, 16 | // providingMembersOf declaration: some DeclGroupSyntax, 17 | // in context: some MacroExpansionContext 18 | // ) throws -> [DeclSyntax] { 19 | // // Implementation as before 20 | // } 21 | //} 22 | -------------------------------------------------------------------------------- /Demo/Demo.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | aps-environment 6 | development 7 | com.apple.developer.aps-environment 8 | development 9 | com.apple.security.app-sandbox 10 | 11 | com.apple.security.application-groups 12 | 13 | group.com.swiftheroes.demo 14 | 15 | com.apple.security.files.user-selected.read-only 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Modifiers/ExternalScreenToolBarModifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/13/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ExternalScreenToolBarModifier: ViewModifier { 11 | var screenManager: ScreenManager 12 | @Binding var showingSheet: Bool 13 | 14 | func body(content: Content) -> some View { 15 | #if os(iOS) 16 | return content 17 | .toolbar { 18 | ExternalScreenToolBar(screenManager: screenManager, showingSheet: $showingSheet) 19 | } 20 | #else 21 | return content 22 | #endif 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Heroes/Sources/MacroMacros/LogPropertyMacro.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LogPropertyMacro.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import SwiftCompilerPlugin 9 | import SwiftSyntax 10 | import SwiftSyntaxBuilder 11 | import SwiftSyntaxMacros 12 | 13 | //public struct LogPropertyMacro: AccessorMacro { 14 | // public static func expansion( 15 | // of node: AttributeSyntax, 16 | // providingAccessorsOf declaration: some DeclSyntaxProtocol, 17 | // in context: some MacroExpansionContext 18 | // ) throws -> [AccessorDeclSyntax] { 19 | // // Implementation for logging property access 20 | // } 21 | //} 22 | -------------------------------------------------------------------------------- /Preview/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | QLIsDataBasedPreview 10 | 11 | QLSupportedContentTypes 12 | 13 | QLSupportsSearchableItems 14 | 15 | 16 | NSExtensionPrincipalClass 17 | $(PRODUCT_MODULE_NAME).PreviewViewController 18 | NSExtensionPointIdentifier 19 | com.apple.quicklook.preview 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Enums/OperatingSystem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/13/24. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum OperatingSystem { 11 | case macOS 12 | case iOS 13 | case tvOS 14 | case watchOS 15 | case visionOS 16 | 17 | #if os(macOS) 18 | public static let current = macOS 19 | #elseif os(iOS) 20 | public static let current = iOS 21 | #elseif os(tvOS) 22 | public static let current = tvOS 23 | #elseif os(watchOS) 24 | public static let current = watchOS 25 | #elseif os(visionOS) 26 | public static let current = visionOS 27 | #else 28 | #error("Unsupported platform") 29 | #endif 30 | } 31 | -------------------------------------------------------------------------------- /Spotlight/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CSExtensionLabel 6 | SpotlightImporter 7 | NSExtension 8 | 9 | NSExtensionAttributes 10 | 11 | CSSupportedContentTypes 12 | 13 | com.example.plain-text 14 | 15 | 16 | NSExtensionPointIdentifier 17 | com.apple.spotlight.import 18 | NSExtensionPrincipalClass 19 | $(PRODUCT_MODULE_NAME).ImportExtension 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/ExternalScreens/ScreenManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import Observation 11 | import HeroShared 12 | 13 | @Observable 14 | public class ScreenManager { 15 | public init() {} 16 | 17 | public var showScreen = false 18 | public var speaker: Speaker = .alex 19 | public var selection: Int = 0 20 | public var speakers: [Speaker] = Speaker.all 21 | 22 | public func add() { 23 | selection += 1 24 | speaker = speakers[selection] 25 | } 26 | 27 | public func minus() { 28 | selection -= 1 29 | speaker = speakers[selection] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Heroes/Sources/Macros/Macros.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Macros.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | //@attached(member, names: named(debugList)) 9 | //public macro DebugList() = #externalMacro(module: "MacroMacros", type: "DebugListMacro") 10 | // 11 | //@attached(accessor) 12 | //public macro LogProperty() = #externalMacro(module: "MacroMacros", type: "LogPropertyMacro") 13 | 14 | //@attached(member, names: named(debugPrintModifier)) 15 | //public macro DebugPrint(_ properties: String...) = #externalMacro(module: "MacroMacros", type: "DebugPrintMacro") 16 | 17 | @attached(member, names: named(body)) 18 | public macro NavigationTitle(_ title: String) = #externalMacro(module: "MacroMacros", type: "NavigationTitleMacro") 19 | -------------------------------------------------------------------------------- /Demo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CoreSpotlightActions 6 | 7 | 8 | CoreSpotlightActionIdentifier 9 | CS_ACTION_1 10 | CoreSpotlightActionSymbolImage 11 | pencil 12 | CoreSpotlightActionTitle 13 | Test Me 14 | 15 | 16 | ITSAppUsesNonExemptEncryption 17 | 18 | NSUserActivityTypes 19 | 20 | com.swiftheroes.speakers 21 | 22 | com.apple.security.app-sandbox 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Demo/Assets.xcassets/Brand Assets.brandassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "assets" : [ 3 | { 4 | "filename" : "App Icon - App Store.imagestack", 5 | "idiom" : "tv", 6 | "role" : "primary-app-icon", 7 | "size" : "1280x768" 8 | }, 9 | { 10 | "filename" : "App Icon.imagestack", 11 | "idiom" : "tv", 12 | "role" : "primary-app-icon", 13 | "size" : "400x240" 14 | }, 15 | { 16 | "filename" : "Top Shelf Image Wide.imageset", 17 | "idiom" : "tv", 18 | "role" : "top-shelf-image-wide", 19 | "size" : "2320x720" 20 | }, 21 | { 22 | "filename" : "Top Shelf Image.imageset", 23 | "idiom" : "tv", 24 | "role" : "top-shelf-image", 25 | "size" : "1920x720" 26 | } 27 | ], 28 | "info" : { 29 | "author" : "xcode", 30 | "version" : 1 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Views/BackgroundView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BackgroundView 2.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import SwiftUI 9 | import HeroShared 10 | 11 | public struct BackgroundView: View { 12 | public init() {} 13 | public var body: some View { 14 | ZStack { 15 | LinearGradient(gradient: Gradient(colors: [.heroOrange,.heroBlue ]), startPoint: .top, endPoint: .bottom) 16 | 17 | VStack { 18 | Image.logo 19 | .cornerRadius(15.0) 20 | 21 | Image.wordLogo 22 | .resizable() 23 | .frame(width: 300, height: 150) 24 | } 25 | } 26 | .ignoresSafeArea() 27 | } 28 | } 29 | 30 | #Preview { 31 | BackgroundView() 32 | } 33 | -------------------------------------------------------------------------------- /Share/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | NSExtensionActivationRule 10 | 11 | NSExtensionActivationDictionaryVersion 12 | 2 13 | NSExtensionActivationSupportsAttachmentsWithMaxCount 14 | 1 15 | NSExtensionActivationSupportsImageWithMaxCount 16 | 17 | 1 18 | 19 | 20 | NSExtensionPointIdentifier 21 | com.apple.share-services 22 | NSExtensionPrincipalClass 23 | $(PRODUCT_MODULE_NAME).ShareViewController 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Resources/Localizable.xcstrings: -------------------------------------------------------------------------------- 1 | { 2 | "sourceLanguage" : "en", 3 | "strings" : { 4 | "" : { 5 | 6 | }, 7 | "👓" : { 8 | 9 | }, 10 | "Bad Image" : { 11 | 12 | }, 13 | "Extensions" : { 14 | 15 | }, 16 | "Found Image" : { 17 | 18 | }, 19 | "Half screen content here" : { 20 | 21 | }, 22 | "Nothing selected" : { 23 | 24 | }, 25 | "Post as Image" : { 26 | 27 | }, 28 | "Speakers" : { 29 | 30 | }, 31 | "Swift Heroes" : { 32 | "localizations" : { 33 | "en" : { 34 | "stringUnit" : { 35 | "state" : "translated", 36 | "value" : "Swift Heroes" 37 | } 38 | }, 39 | "it" : { 40 | "stringUnit" : { 41 | "state" : "translated", 42 | "value" : "Eroi rapidi" 43 | } 44 | } 45 | } 46 | } 47 | }, 48 | "version" : "1.0" 49 | } -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/heroBlue.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "display-p3", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.400", 9 | "green" : "0.215", 10 | "red" : "0.080" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "display-p3", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.400", 27 | "green" : "0.215", 28 | "red" : "0.080" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Resources/Assets.xcassets/heroOrange.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "color" : { 5 | "color-space" : "display-p3", 6 | "components" : { 7 | "alpha" : "1.000", 8 | "blue" : "0.306", 9 | "green" : "0.428", 10 | "red" : "0.929" 11 | } 12 | }, 13 | "idiom" : "universal" 14 | }, 15 | { 16 | "appearances" : [ 17 | { 18 | "appearance" : "luminosity", 19 | "value" : "dark" 20 | } 21 | ], 22 | "color" : { 23 | "color-space" : "display-p3", 24 | "components" : { 25 | "alpha" : "1.000", 26 | "blue" : "0.306", 27 | "green" : "0.427", 28 | "red" : "0.925" 29 | } 30 | }, 31 | "idiom" : "universal" 32 | } 33 | ], 34 | "info" : { 35 | "author" : "xcode", 36 | "version" : 1 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/AppDelegate+QuickActions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate+QuickActions.swift 3 | // Demo 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import Foundation 9 | 10 | #if os(iOS) 11 | import UIKit 12 | 13 | public extension AppDelegate { 14 | public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 15 | 16 | if let shortcutItem = options.shortcutItem { 17 | print("App delegate quick action") 18 | 19 | QuickActionsManager.shared.handleQaItem(type: shortcutItem.type) 20 | 21 | } 22 | 23 | 24 | let sceneConfiguration = UISceneConfiguration(name: "Custom Configuration", sessionRole: connectingSceneSession.role) 25 | sceneConfiguration.delegateClass = SceneDelegate.self 26 | 27 | return sceneConfiguration 28 | } 29 | } 30 | #endif 31 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcuserdata/u380112.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 9 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Notification/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | UNNotificationExtensionCategory 10 | 11 | images 12 | flightStatus 13 | video 14 | default 15 | 16 | UNNotificationExtensionDefaultContentHidden 17 | 18 | UNNotificationExtensionInitialContentSizeRatio 19 | 0.25 20 | UNNotificationExtensionUserInteractionEnabled 21 | 22 | 23 | NSExtensionPointIdentifier 24 | com.apple.usernotifications.content-extension 25 | NSExtensionPrincipalClass 26 | $(PRODUCT_MODULE_NAME).NotificationViewController 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Notification/NotificationViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationViewController.swift 3 | // Notification 4 | // 5 | // Created by Vince Davis on 4/7/24. 6 | // 7 | 8 | import HeroiOS 9 | import HeroShared 10 | import SwiftUI 11 | 12 | #if os(macOS) 13 | import AppKit 14 | 15 | class NotificationViewController: NSViewController { 16 | 17 | var viewModel: NotificationModel = .init() 18 | 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | preferredContentSize = CGSize(width: 320, height: 300) 22 | self.add(swiftUIView: AnyView(NotificationView(viewModel: viewModel))) 23 | } 24 | } 25 | #endif 26 | 27 | #if os(iOS) || os(visionOS) 28 | import UIKit 29 | 30 | class NotificationViewController: UIViewController { 31 | var viewModel: NotificationModel = .init() 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | preferredContentSize = CGSize(width: 320, height: 300) 36 | self.add(swiftUIView: AnyView(NotificationView(viewModel: viewModel))) 37 | } 38 | } 39 | #endif 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Swift Heroes Demo App 2 | 3 | This is from my talk "Don't forget about me!" at Swift Heroes '24 4 | 5 | 6 | Share & Action Extensions 7 | https://medium.com/@henribredtprivat/create-an-ios-share-extension-with-custom-ui-in-swift-and-swiftui-2023-6cf069dc1209 8 | https://medium.com/@cmoulinet/ios-share-extension-custom-rules-to-limit-type-or-numbers-of-medias-selected-91ab596d505 9 | 10 | Spotlight & Handoff 11 | https://www.hackingwithswift.com/quick-start/swiftui/how-to-continue-an-nsuseractivity-in-swiftui 12 | https://swiftui-lab.com/nsuseractivity-with-swiftui/ 13 | https://betterprogramming.pub/implement-core-spotlight-in-a-swiftui-app-859cb703f55d 14 | 15 | AppClips 16 | https://developer.apple.com/documentation/app_clips/creating_an_app_clip_with_xcode 17 | 18 | Quick Actions 19 | https://medium.com/appcent/add-quick-actions-to-swiftui-app-4498df911b93 20 | 21 | Message * Outdated for Views but other content is good. 22 | https://www.oreilly.com/library/view/ios-10-swift/9781491966426/ch01.html 23 | 24 | External Screen 25 | https://useyourloaf.com/blog/swiftui-supporting-external-screens/ 26 | 27 | Notifications 28 | https://www.avanderlee.com/swift/rich-notifications/ 29 | 30 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/ExternalScreens/ExternalScreenToolBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/13/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | struct ExternalScreenToolBar: ToolbarContent { 11 | var screenManager: ScreenManager 12 | @Binding var showingSheet: Bool 13 | 14 | var body: some ToolbarContent { 15 | #if os(iOS) 16 | ToolbarItem(placement: .topBarLeading) { 17 | Text("👓") 18 | .font(.largeTitle) 19 | } 20 | ToolbarItem(placement: .topBarTrailing) { 21 | if screenManager.showScreen { 22 | Button(action: { 23 | showingSheet = true 24 | }, label: { 25 | Image(systemName: "airplayvideo") 26 | .font(.title3) 27 | .symbolRenderingMode(.palette) 28 | .foregroundStyle(.black, .blue) 29 | .symbolEffect(.pulse.byLayer, isActive: true) 30 | }) 31 | } 32 | } 33 | #else 34 | ToolbarItem(placement: .automatic) { 35 | Text("") 36 | .font(.largeTitle) 37 | } 38 | #endif 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Action/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSExtension 6 | 7 | NSExtensionAttributes 8 | 9 | NSExtensionActivationRule 10 | 11 | NSExtensionActivationDictionaryVersion 12 | 2 13 | NSExtensionActivationSupportsAttachmentsWithMaxCount 14 | 1 15 | NSExtensionActivationSupportsImageWithMaxCount 16 | 17 | 1 18 | 19 | NSExtensionServiceAllowsFinderPreviewItem 20 | 21 | NSExtensionServiceAllowsTouchBarItem 22 | 23 | NSExtensionServiceFinderPreviewIconName 24 | NSActionTemplate 25 | NSExtensionServiceTouchBarBezelColorName 26 | TouchBarBezel 27 | NSExtensionServiceTouchBarIconName 28 | NSActionTemplate 29 | 30 | NSExtensionPointIdentifier 31 | com.apple.ui-services 32 | NSExtensionPrincipalClass 33 | $(PRODUCT_MODULE_NAME).ActionViewController 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Modifiers/ForegroundViewModifier.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import SwiftUI 9 | import Combine 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #endif 14 | 15 | struct ForegroundViewModifier: ViewModifier where ScreenContent: View { 16 | @Binding var inBackground: Bool 17 | let screenContent: () -> ScreenContent 18 | 19 | #if os(iOS) 20 | @Environment(\.scenePhase) var scenePhase 21 | 22 | func body(content: Content) -> some View { 23 | content 24 | .onChange(of: scenePhase) { _, newPhase in 25 | if newPhase == .inactive { 26 | print("Inactive") 27 | inBackground = true 28 | } else if newPhase == .active { 29 | print("Active") 30 | inBackground = false 31 | } else if newPhase == .background { 32 | print("Background") 33 | inBackground = true 34 | } 35 | } 36 | .fullScreenCover(isPresented: $inBackground, content: { 37 | screenContent() 38 | }) 39 | .transaction({ transaction in 40 | transaction.disablesAnimations = true 41 | }) 42 | } 43 | #else 44 | func body(content: Content) -> some View { 45 | content 46 | } 47 | #endif 48 | } 49 | -------------------------------------------------------------------------------- /Heroes/Tests/MacroTests/MacroTests.swift: -------------------------------------------------------------------------------- 1 | import SwiftSyntax 2 | import SwiftSyntaxBuilder 3 | import SwiftSyntaxMacros 4 | import SwiftSyntaxMacrosTestSupport 5 | import XCTest 6 | 7 | // Macro implementations build for the host, so the corresponding module is not available when cross-compiling. Cross-compiled tests may still make use of the macro itself in end-to-end tests. 8 | #if canImport(MacroMacros) 9 | import MacroMacros 10 | 11 | 12 | #endif 13 | 14 | final class MacroTests: XCTestCase { 15 | // func testMacro() throws { 16 | // #if canImport(MyMacroMacros) 17 | // assertMacroExpansion( 18 | // """ 19 | // #stringify(a + b) 20 | // """, 21 | // expandedSource: """ 22 | // (a + b, "a + b") 23 | // """, 24 | // macros: testMacros 25 | // ) 26 | // #else 27 | // throw XCTSkip("macros are only supported when running tests for the host platform") 28 | // #endif 29 | // } 30 | // 31 | // func testMacroWithStringLiteral() throws { 32 | // #if canImport(MyMacroMacros) 33 | // assertMacroExpansion( 34 | // #""" 35 | // #stringify("Hello, \(name)") 36 | // """#, 37 | // expandedSource: #""" 38 | // ("Hello, \(name)", #""Hello, \(name)""#) 39 | // """#, 40 | // macros: testMacros 41 | // ) 42 | // #else 43 | // throw XCTSkip("macros are only supported when running tests for the host platform") 44 | // #endif 45 | // } 46 | } 47 | -------------------------------------------------------------------------------- /Preview/PreviewViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreviewViewController.swift 3 | // Preview 4 | // 5 | // Created by Vince Davis on 4/15/24. 6 | // 7 | 8 | import UIKit 9 | import QuickLook 10 | import HeroiOS 11 | import SwiftUI 12 | 13 | class PreviewViewController: UIViewController, QLPreviewingController { 14 | 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | // Do any additional setup after loading the view. 18 | } 19 | 20 | func preparePreviewOfSearchableItem(identifier: String, queryString: String?, completionHandler handler: @escaping (Error?) -> Void) { 21 | // Perform any setup necessary in order to prepare the view. 22 | 23 | // Call the completion handler so Quick Look knows that the preview is fully loaded. 24 | // Quick Look will display a loading spinner while the completion handler is not called. 25 | self.add(swiftUIView: AnyView(PreviewItemView(identifier: identifier))) 26 | handler(nil) 27 | } 28 | 29 | 30 | func preparePreviewOfFile(at url: URL, completionHandler handler: @escaping (Error?) -> Void) { 31 | // Add the supported content types to the QLSupportedContentTypes array in the Info.plist of the extension. 32 | 33 | // Perform any setup necessary in order to prepare the view. 34 | 35 | // Call the completion handler so Quick Look knows that the preview is fully loaded. 36 | // Quick Look will display a loading spinner while the completion handler is not called. 37 | handler(nil) 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/QuickActions/QuickActionsManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import Foundation 9 | import Observation 10 | 11 | #if os(iOS) 12 | import UIKit 13 | #endif 14 | 15 | @Observable 16 | public class QuickActionsManager { 17 | public static let shared = QuickActionsManager() 18 | public init() {} 19 | 20 | public var quickAction: QuickAction? = nil 21 | 22 | public func handleQaItem(type: String) { 23 | if type == "share" { 24 | quickAction = .share 25 | } else if type == "alberto" { 26 | quickAction = .alberto 27 | } 28 | } 29 | 30 | public func addQuickActions() { 31 | #if os(iOS) 32 | UIApplication.shared.shortcutItems = [ 33 | UIApplicationShortcutItem(type: "share", 34 | localizedTitle: "Show Share", 35 | localizedSubtitle: "Show Share for Extensions", 36 | icon: UIApplicationShortcutIcon.init(systemImageName: "square.and.arrow.up")), 37 | UIApplicationShortcutItem(type: "alberto", 38 | localizedTitle: "Show Alberto", 39 | localizedSubtitle: "Show Speaker Profile for Alberto", 40 | icon: UIApplicationShortcutIcon.init(systemImageName: "music.mic")), 41 | ] 42 | #endif 43 | } 44 | } 45 | 46 | public enum QuickAction: String, Hashable { 47 | case share 48 | case alberto 49 | } 50 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/ExternalScreens/ExternalScreenView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import HeroShared 11 | 12 | public struct ExternalScreenView: View { 13 | public init() {} 14 | 15 | @Environment(ScreenManager.self) 16 | public var screenManager: ScreenManager 17 | 18 | @State var speaker: Speaker = .alex 19 | 20 | public var body: some View { 21 | ZStack { 22 | LinearGradient(gradient: Gradient(colors: [.heroOrange, .heroBlue]), startPoint: .top, endPoint: .bottom) 23 | 24 | VStack { 25 | HStack { 26 | Image.logo 27 | .resizable() 28 | .frame(width: 75, height: 75) 29 | .cornerRadius(10.0) 30 | 31 | Image.wordLogo 32 | .resizable() 33 | .frame(width: 300, height: 100) 34 | } 35 | .padding() 36 | 37 | speaker.image 38 | .resizable() 39 | .frame(width: 290, height: 290) 40 | .cornerRadius(15.0) 41 | 42 | Text(speaker.name) 43 | .font(.largeTitle) 44 | .bold() 45 | 46 | Spacer() 47 | } 48 | } 49 | .ignoresSafeArea() 50 | .onChange(of: screenManager.speaker) { _, newValue in 51 | speaker = newValue 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Extensions/UIViewController+Extensions.swift: -------------------------------------------------------------------------------- 1 | 2 | import SwiftUI 3 | 4 | #if os(iOS) || os(visionOS) 5 | import UIKit 6 | public extension UIViewController { 7 | func add(swiftUIView: AnyView) { 8 | let childView = UIHostingController(rootView: AnyView(swiftUIView)) 9 | addChild(childView) 10 | view.addSubview(childView.view) 11 | childView.didMove(toParent: self) 12 | 13 | childView.view.translatesAutoresizingMaskIntoConstraints = false 14 | childView.view.heightAnchor.constraint(equalTo: self.view.heightAnchor).isActive = true 15 | childView.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true 16 | childView.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true 17 | childView.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true 18 | } 19 | } 20 | #elseif os(macOS) 21 | import AppKit 22 | public extension NSViewController { 23 | func add(swiftUIView: AnyView) { 24 | let childView = NSHostingController(rootView: AnyView(swiftUIView)) 25 | addChild(childView) 26 | view.addSubview(childView.view) 27 | 28 | childView.view.translatesAutoresizingMaskIntoConstraints = false 29 | childView.view.heightAnchor.constraint(equalTo: self.view.heightAnchor).isActive = true 30 | childView.view.leftAnchor.constraint(equalTo: self.view.leftAnchor).isActive = true 31 | childView.view.rightAnchor.constraint(equalTo: self.view.rightAnchor).isActive = true 32 | childView.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true 33 | } 34 | } 35 | #endif 36 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Views/PreviewItemView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PreviewItemView.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/15/24. 6 | // 7 | 8 | import SwiftUI 9 | import HeroShared 10 | 11 | public struct PreviewItemView: View { 12 | public var identifier: String 13 | public init(identifier: String) { 14 | self.identifier = identifier 15 | } 16 | 17 | public var body: some View { 18 | if let speaker = Speaker.all.filter({ $0.id == identifier }).first { 19 | ZStack { 20 | LinearGradient(gradient: Gradient(colors: [.heroOrange, .heroBlue]), startPoint: .top, endPoint: .bottom) 21 | 22 | VStack { 23 | HStack { 24 | Image.logo 25 | .resizable() 26 | .frame(width: 100, height: 100) 27 | .cornerRadius(15.0) 28 | 29 | Image.wordLogo 30 | .resizable() 31 | .frame(height: 150) 32 | } 33 | .padding() 34 | 35 | speaker.image 36 | .resizable() 37 | .frame(width: 300, height: 300) 38 | .cornerRadius(15.0) 39 | 40 | Text(speaker.name) 41 | .font(.largeTitle) 42 | .bold() 43 | } 44 | } 45 | .ignoresSafeArea() 46 | } 47 | } 48 | } 49 | 50 | #Preview { 51 | PreviewItemView(identifier: "1") 52 | } 53 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Extensions/View+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import HeroShared 11 | 12 | public extension View { 13 | func externalScreen(_ showingExternalScreen: Binding, screenContent: @escaping () -> ScreenContent) -> some View where ScreenContent: View { 14 | modifier(ExternalScreenViewModifier(showingExternalScreen: showingExternalScreen, screenContent: screenContent)) 15 | } 16 | 17 | func backgroundScreen(_ inBackground: Binding, screenContent: @escaping () -> ScreenContent) -> some View where ScreenContent: View { 18 | modifier(ForegroundViewModifier(inBackground: inBackground, screenContent: screenContent)) 19 | } 20 | 21 | func externalScreenToolbar(screenManager: ScreenManager, showingSheet: Binding) -> some View { 22 | return self.modifier(ExternalScreenToolBarModifier(screenManager: screenManager, showingSheet: showingSheet)) 23 | } 24 | 25 | @ViewBuilder 26 | func ifOS(_ operatingSystems: OperatingSystem...,modifier: (Self) -> Content) -> some View { 27 | if operatingSystems.contains(OperatingSystem.current) { 28 | modifier(self) 29 | } else { 30 | self 31 | } 32 | } 33 | 34 | func modify(@ViewBuilder modifier: (Self) -> T) -> T { 35 | modifier(self) 36 | } 37 | 38 | func customToolBarStyle() -> some View { 39 | self 40 | #if os(iOS) 41 | .toolbarBackground(Color.heroOrange.gradient, for: .navigationBar) 42 | .toolbarBackground(.visible, for: .navigationBar) 43 | #endif 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Heroes/Sources/MacroMacros/NavigationTitleMacro.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NavigationTitleMacro.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | import SwiftCompilerPlugin 9 | import SwiftSyntax 10 | import SwiftSyntaxBuilder 11 | import SwiftSyntaxMacros 12 | 13 | public struct NavigationTitleMacro: MemberMacro { 14 | public static func expansion( 15 | of node: AttributeSyntax, 16 | providingMembersOf declaration: some DeclGroupSyntax, 17 | in context: some MacroExpansionContext 18 | ) throws -> [DeclSyntax] { 19 | guard let argument = node.arguments?.as(LabeledExprListSyntax.self)?.first?.expression, 20 | let stringLiteral = argument.as(StringLiteralExprSyntax.self)?.segments.first?.as(StringSegmentSyntax.self)?.content else { 21 | throw MacroError.invalidArgument 22 | } 23 | 24 | let titleValue = stringLiteral.text 25 | 26 | let newBodyCode = """ 27 | var body: some View { 28 | NavigationView { 29 | VStack { 30 | Text("Name") 31 | } 32 | .navigationTitle("\(titleValue)") 33 | } 34 | } 35 | """ 36 | 37 | return [DeclSyntax(stringLiteral: newBodyCode)] 38 | } 39 | } 40 | 41 | public enum MacroError: Error, CustomStringConvertible { 42 | case invalidArgument 43 | 44 | public var description: String { 45 | switch self { 46 | case .invalidArgument: 47 | return "The NavigationTitle macro requires a string literal argument." 48 | } 49 | } 50 | } 51 | 52 | @main 53 | struct MacrosPlugin: CompilerPlugin { 54 | let providingMacros: [Macro.Type] = [ 55 | NavigationTitleMacro.self 56 | // Add more macros here 57 | ] 58 | } 59 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcuserdata/vince.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Action.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | AppClips.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 7 16 | 17 | Demo.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 1 21 | 22 | HeroesWatch Watch App.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 8 26 | 27 | My Cool Extension.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 12 31 | 32 | NewExtension.xcscheme_^#shared#^_ 33 | 34 | orderHint 35 | 13 36 | 37 | Notification.xcscheme_^#shared#^_ 38 | 39 | orderHint 40 | 3 41 | 42 | NotificationService.xcscheme_^#shared#^_ 43 | 44 | orderHint 45 | 4 46 | 47 | Preview.xcscheme_^#shared#^_ 48 | 49 | orderHint 50 | 10 51 | 52 | Share.xcscheme_^#shared#^_ 53 | 54 | orderHint 55 | 5 56 | 57 | Spotlight.xcscheme_^#shared#^_ 58 | 59 | orderHint 60 | 6 61 | 62 | iMessage.xcscheme_^#shared#^_ 63 | 64 | orderHint 65 | 2 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /Demo/DemoApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DemoApp.swift 3 | // Demo 4 | // 5 | // Created by Vince Davis on 4/7/24. 6 | // 7 | 8 | import SwiftUI 9 | import UserNotifications 10 | import CoreSpotlight 11 | import Observation 12 | import HeroiOS 13 | import HeroShared 14 | import Macros 15 | 16 | @main 17 | struct DemoApp: App { 18 | #if !os(tvOS) && !os(macOS) 19 | @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 20 | #endif 21 | @Environment(\.scenePhase) var scenePhase 22 | 23 | @State var inBackground: Bool = false 24 | 25 | init() { 26 | print("Main first") 27 | } 28 | 29 | var body: some Scene { 30 | WindowGroup { 31 | if #available(iOS 17.0, *) { 32 | if inBackground { 33 | BackgroundView() 34 | } else { 35 | //MainView() 36 | UserProfileView() 37 | } 38 | } else if #available(macOS 14.0, *) { 39 | MainView() 40 | } else if #available(tvOS 17.0, *) { 41 | if inBackground { 42 | BackgroundView() 43 | } else { 44 | MainView() 45 | } 46 | } else if #available(visionOS 1.0, *){ 47 | MainView() 48 | } else { 49 | MainView() 50 | } 51 | } 52 | .onChange(of: scenePhase) { _, newPhase in 53 | switch newPhase { 54 | case .background: 55 | inBackground = true 56 | if #available(iOS 17.0, *) { 57 | QuickActionsManager.shared.addQuickActions() 58 | } 59 | case .inactive: 60 | inBackground = true 61 | case .active: 62 | inBackground = false 63 | @unknown default: 64 | inBackground = false 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /Heroes/Sources/MacroMacros/DebugPrintMacro.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DebugPrintMacro.swift 3 | // Heroes 4 | // 5 | // Created by Vince Davis on 9/5/24. 6 | // 7 | 8 | //import SwiftCompilerPlugin 9 | //import SwiftSyntax 10 | //import SwiftSyntaxBuilder 11 | //import SwiftSyntaxMacros 12 | // 13 | //public struct DebugPrintMacro: MemberMacro { 14 | // public static func expansion( 15 | // of node: AttributeSyntax, 16 | // providingMembersOf declaration: some DeclGroupSyntax, 17 | // in context: some MacroExpansionContext 18 | // ) throws -> [DeclSyntax] { 19 | // guard let structDecl = declaration.as(StructDeclSyntax.self) else { 20 | // throw MacroError.notAStruct 21 | // } 22 | // 23 | // let properties = node.arguments?.as(LabeledExprListSyntax.self)?.map { $0.expression.description } ?? [] 24 | // 25 | // let propertyChecks = properties.map { property in 26 | // """ 27 | // if !properties.contains("\(property)") { 28 | // fatalError("Property '\(property)' is not defined in the view.") 29 | // } 30 | // """ 31 | // }.joined(separator: "\n") 32 | // 33 | // let propertyPrints = properties.map { property in 34 | // "print(\"\\($0): \\(String(describing: self.\(property)))\")" 35 | // }.joined(separator: "\n ") 36 | // 37 | // let modifierCode = """ 38 | // func debugPrintModifier() -> some View { 39 | // let properties = Set(Mirror(reflecting: self).children.compactMap { $0.label }) 40 | // \(propertyChecks) 41 | // return self.modifier(DebugPrintModifier(action: { 42 | // print("Debug Print for \\(String(describing: Self.self)):") 43 | // \(propertyPrints) 44 | // })) 45 | // } 46 | // """ 47 | // 48 | // return [DeclSyntax(stringLiteral: modifierCode)] 49 | // } 50 | //} 51 | // 52 | //public enum MacroError: Error { 53 | // case notAStruct 54 | //} 55 | -------------------------------------------------------------------------------- /Notification/NotificationViewController+UserNotifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationViewController+UserNotifications.swift 3 | // Notification 4 | // 5 | // Created by Vince Davis on 4/13/24. 6 | // 7 | 8 | #if canImport(UserNotifications) 9 | import UserNotifications 10 | import UserNotificationsUI 11 | 12 | extension NotificationViewController: UNNotificationContentExtension { 13 | func didReceive(_ notification: UNNotification) { 14 | let cat = notification.request.content.categoryIdentifier 15 | 16 | viewModel.catergory = cat 17 | } 18 | 19 | func didReceive(_ response: UNNotificationResponse, completionHandler completion: @escaping (UNNotificationContentExtensionResponseOption) -> Void) { 20 | if response.actionIdentifier == "testNotification.changeAction" { 21 | //self.scrollNextItem() 22 | viewModel.changeRating() 23 | completion(UNNotificationContentExtensionResponseOption.doNotDismiss) 24 | } else if response.actionIdentifier == "testNotification.playAction" { 25 | //self.scrollPreviousItem() 26 | viewModel.play() 27 | completion(UNNotificationContentExtensionResponseOption.doNotDismiss) 28 | } else if response.actionIdentifier == "testNotification.slideAction" { 29 | //self.scrollPreviousItem() 30 | viewModel.slide() 31 | completion(UNNotificationContentExtensionResponseOption.doNotDismiss) 32 | } else if response.actionIdentifier == "testNotification.pauseAction" { 33 | //self.scrollPreviousItem() 34 | viewModel.pause() 35 | completion(UNNotificationContentExtensionResponseOption.doNotDismiss) 36 | } else if response.actionIdentifier == "testNotification.submitAction" { 37 | //self.scrollPreviousItem() 38 | completion(UNNotificationContentExtensionResponseOption.dismiss) 39 | } else { 40 | //completion(UNNotificationContentExtensionResponseOption.dismissAndForwardAction) 41 | completion(UNNotificationContentExtensionResponseOption.doNotDismiss) 42 | } 43 | } 44 | } 45 | #endif 46 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/AppDelegate+Notifications.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate+Notifications.swift 3 | // Demo 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import Foundation 9 | 10 | #if os(iOS) || os(visionOS) || os(macOS) 11 | import UserNotifications 12 | 13 | public extension AppDelegate { 14 | public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { 15 | let userInfo = notification.request.content.userInfo 16 | print("Receive notification in the foreground \(userInfo)") 17 | let pref = UserDefaults.init(suiteName: "group.id.gits.notifserviceextension") 18 | pref?.set(userInfo, forKey: "NOTIF_DATA") 19 | //guard let vc = UIApplication.shared.windows.first?.rootViewController as? ViewController else { return } 20 | //vc.handleNotifData() 21 | completionHandler([.alert, .badge, .sound]) 22 | } 23 | 24 | public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { 25 | let userInfo = response.notification.request.content.userInfo 26 | //if let customData = userInfo["customData"] as? String { 27 | //print("Custom data received: \(customData)") 28 | 29 | switch response.actionIdentifier { 30 | case UNNotificationDefaultActionIdentifier: 31 | // the user swiped to unlock 32 | print("Default identifier") 33 | case "testNotification.doneAction": 34 | // the user tapped our "show more info…" button 35 | print("Done more information…") 36 | case "testNotification.openAction": 37 | // the user tapped our "show more info…" button 38 | print("Open more information…") 39 | default: 40 | break 41 | } 42 | // } 43 | completionHandler() 44 | } 45 | } 46 | #endif 47 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Data/ListItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ListItem.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | public struct ListItem: Identifiable, Hashable, Listable { 12 | public init(id: String, title: String, subtitle: String, image: Image, badges: [String], type: ListType, items: [ListItem]? = nil) { 13 | self.id = id 14 | self.title = title 15 | self.subtitle = subtitle 16 | self.image = image 17 | self.badges = badges 18 | self.type = type 19 | self.items = items 20 | } 21 | 22 | public var id: String 23 | public var title: String 24 | public var subtitle: String 25 | public var image: Image 26 | public var badges: [String] 27 | public var type: ListType 28 | public var items: [ListItem]? 29 | 30 | public func hash(into hasher: inout Hasher) { 31 | return hasher.combine(id) 32 | } 33 | 34 | public static func == (lhs: ListItem, rhs: ListItem) -> Bool { 35 | return lhs.id == rhs.id 36 | } 37 | } 38 | 39 | public extension ListItem { 40 | static let speakers = ListItem(id: "1000", 41 | title: "Speakers", 42 | subtitle: "Swift Hero Speakers", 43 | image: Image(systemName: "person.3.fill"), 44 | badges: [], 45 | type: .sectionHeader, 46 | items: Speaker.all.map({ ListItem(id : $0.id, title: $0.title, subtitle: $0.subtitle, image: $0.image, badges: [], type: .speaker) })) 47 | 48 | static let extensions = ListItem(id: "2000", 49 | title: "Extensions", 50 | subtitle: "Extensions covered in Talk", 51 | image: Image(systemName: "puzzlepiece.extension.fill"), 52 | badges: [], 53 | type: .sectionHeader, 54 | items: ExtensionItem.all.map({ ListItem(id : $0.id, title: $0.title, subtitle: $0.subtitle, image: $0.image, badges: $0.platforms, type: .extensionItem) })) 55 | } 56 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Modifiers/ExternalScreenViewModifier.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import Combine 3 | #if os(iOS) 4 | import UIKit 5 | #endif 6 | 7 | public struct ExternalScreenViewModifier: ViewModifier where ScreenContent: View { 8 | @Binding var showingExternalScreen: Bool 9 | let screenContent: () -> ScreenContent 10 | 11 | #if os(iOS) 12 | @State var additionalWindows: [UIWindow] = [] 13 | 14 | public func body(content: Content) -> some View { 15 | content 16 | .onReceive( 17 | screenDidConnectPublisher, 18 | perform: screenDidConnect 19 | ) 20 | .onReceive( 21 | screenDidDisconnectPublisher, 22 | perform: screenDidDisconnect 23 | ) 24 | } 25 | 26 | private var screenDidConnectPublisher: AnyPublisher { 27 | NotificationCenter.default 28 | .publisher(for: UIScreen.didConnectNotification) 29 | .compactMap { $0.object as? UIScreen } 30 | .receive(on: RunLoop.main) 31 | .eraseToAnyPublisher() 32 | } 33 | 34 | private var screenDidDisconnectPublisher: AnyPublisher { 35 | NotificationCenter.default 36 | .publisher(for: UIScreen.didDisconnectNotification) 37 | .compactMap { $0.object as? UIScreen } 38 | .receive(on: RunLoop.main) 39 | .eraseToAnyPublisher() 40 | } 41 | 42 | private func screenDidConnect(_ screen: UIScreen) { 43 | let window = UIWindow(frame: screen.bounds) 44 | 45 | window.windowScene = UIApplication.shared.connectedScenes 46 | .first { ($0 as? UIWindowScene)?.screen == screen } 47 | as? UIWindowScene 48 | 49 | let controller = UIHostingController(rootView: screenContent()) 50 | window.rootViewController = controller 51 | window.isHidden = false 52 | additionalWindows.append(window) 53 | showingExternalScreen = true 54 | } 55 | 56 | private func screenDidDisconnect(_ screen: UIScreen) { 57 | additionalWindows.removeAll { $0.screen == screen } 58 | showingExternalScreen = false 59 | } 60 | #else 61 | public func body(content: Content) -> some View { 62 | content 63 | } 64 | #endif 65 | } 66 | -------------------------------------------------------------------------------- /Heroes/Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version: 5.10 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | import CompilerPluginSupport 6 | 7 | let package = Package( 8 | name: "Heroes", 9 | defaultLocalization: "en", 10 | platforms: [.macOS(.v12), .iOS(.v17), .watchOS(.v10), .visionOS(.v1)], 11 | products: [ 12 | // Products define the executables and libraries a package produces, making them visible to other packages. 13 | .library( 14 | name: "HeroShared", 15 | targets: ["HeroShared"]), 16 | .library( 17 | name: "HeroiOS", 18 | targets: ["HeroiOS"]), 19 | .library( 20 | name: "Macros", 21 | targets: ["Macros"] 22 | ), 23 | .executable( 24 | name: "MacroClient", 25 | targets: ["MacroClient"] 26 | ), 27 | ], 28 | dependencies: [ 29 | .package(url: "https://github.com/swiftlang/swift-syntax.git", from: "509.0.0"), 30 | ], 31 | targets: [ 32 | // Targets are the basic building blocks of a package, defining a module or a test suite. 33 | // Targets can depend on other targets in this package and products from dependencies. 34 | .target( 35 | name: "HeroShared"), 36 | .testTarget( 37 | name: "HeroSharedTests", 38 | dependencies: ["HeroShared"]), 39 | .target( 40 | name: "HeroiOS", 41 | dependencies: ["HeroShared"]), 42 | .testTarget( 43 | name: "HeroiOSTests", 44 | dependencies: ["HeroiOS", "HeroShared"]), 45 | .macro( 46 | name: "MacroMacros", 47 | dependencies: [ 48 | .product(name: "SwiftSyntaxMacros", package: "swift-syntax"), 49 | .product(name: "SwiftCompilerPlugin", package: "swift-syntax") 50 | ] 51 | ), 52 | .target(name: "Macros", dependencies: ["MacroMacros"]), 53 | .executableTarget(name: "MacroClient", dependencies: ["Macros"]), 54 | .testTarget( 55 | name: "MacroTests", 56 | dependencies: [ 57 | "MacroMacros", 58 | .product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"), 59 | ] 60 | ), 61 | ] 62 | ) 63 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Views/MessageView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MessageView.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/14/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | import HeroShared 11 | 12 | struct MessageItem: Hashable { 13 | let id: UUID = .init() 14 | let image: Image 15 | 16 | public func hash(into hasher: inout Hasher) { 17 | return hasher.combine(id) 18 | } 19 | } 20 | 21 | public struct MessageView: View { 22 | public init(action: @escaping ((Image, Bool) -> Void)) { 23 | self.action = action 24 | } 25 | 26 | @State var postAsImage: Bool = true 27 | 28 | let items: [MessageItem] = [ 29 | .init(image: .logo), 30 | .init(image: .wordLogo), 31 | .init(image: .alex), 32 | .init(image: .alberto), 33 | .init(image: .ios3), 34 | .init(image: .ios4), 35 | .init(image: .ios8), 36 | .init(image: .ios9), 37 | .init(image: .ios10), 38 | .init(image: .ios14) 39 | ] 40 | 41 | public var action: ((Image, Bool) -> Void) 42 | let columns = [ 43 | GridItem(.flexible()), 44 | GridItem(.flexible()), 45 | ] 46 | 47 | public var body: some View { 48 | ZStack { 49 | LinearGradient(gradient: Gradient(colors: [.heroOrange,.heroBlue ]), startPoint: .top, endPoint: .bottom) 50 | VStack { 51 | Toggle("Post as Image", isOn: $postAsImage) 52 | .bold() 53 | 54 | ScrollView { 55 | LazyVGrid(columns: columns, spacing: 20) { 56 | ForEach(items, id: \.self) { item in 57 | Button(action: { 58 | action(item.image, postAsImage) 59 | }, label: { 60 | item.image 61 | .resizable() 62 | .frame(width: 150, height: 150) 63 | .aspectRatio(contentMode: .fit) 64 | .cornerRadius(10.0) 65 | }) 66 | } 67 | } 68 | } 69 | } 70 | .padding() 71 | } 72 | .ignoresSafeArea() 73 | } 74 | } 75 | 76 | #Preview { 77 | MessageView(action: { _,_ in }) 78 | } 79 | -------------------------------------------------------------------------------- /HeroesWatch Watch App/ContentView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ContentView.swift 3 | // HeroesWatch Watch App 4 | // 5 | // Created by Vince Davis on 4/11/24. 6 | // 7 | 8 | import SwiftUI 9 | import UserNotifications 10 | import HeroShared 11 | 12 | let activityType = "com.swiftheroes.speakers" 13 | 14 | struct ContentView: View { 15 | @State var selectedItem: ListItem? = nil 16 | 17 | @State var items: [ListItem] = Speaker.all.map({ ListItem(id: $0.id, title: $0.title, subtitle: $0.subtitle, image: $0.image, badges: [], type: .speaker, items: nil)}) 18 | var body: some View { 19 | NavigationSplitView(sidebar: { 20 | List(items, selection: $selectedItem) { item in 21 | NavigationLink(value: item, label: { 22 | HStack { 23 | item.image.resizable().frame(width: 20, height: 20) 24 | Text(item.title) 25 | } 26 | .containerBackground(Color.heroOrange.gradient, for: .navigation) 27 | }) 28 | } 29 | }, detail: { 30 | if let item = selectedItem { 31 | VStack { 32 | item.image.resizable() 33 | 34 | Text(item.title) 35 | } 36 | .containerBackground(Color.heroOrange.gradient, for: .navigation) 37 | .userActivity(activityType, element: item, { element, activity in 38 | let bundleid = Bundle.main.bundleIdentifier ?? "" 39 | activity.addUserInfoEntries(from: ["id": item.id, 40 | "name": item.title, 41 | "setby": bundleid]) 42 | //activity.el 43 | logUserActivity(activity, label: "Item") 44 | }) 45 | } 46 | }) 47 | .task { 48 | let center = UNUserNotificationCenter.current() 49 | _ = try? await center.requestAuthorization( 50 | options: [.alert, .sound, .badge] 51 | ) 52 | } 53 | 54 | } 55 | 56 | func logUserActivity(_ activity: NSUserActivity, label: String = "") { 57 | print("\(label) TYPE = \(activity.activityType)") 58 | print("\(label) INFO = \(activity.userInfo ?? [:])") 59 | } 60 | } 61 | 62 | #Preview { 63 | ContentView() 64 | } 65 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcuserdata/u380112.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Action.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 2 11 | 12 | AppClips.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 8 16 | 17 | Demo.xcscheme_^#shared#^_ 18 | 19 | orderHint 20 | 6 21 | 22 | HeroesWatch Watch App.xcscheme_^#shared#^_ 23 | 24 | orderHint 25 | 9 26 | 27 | Notification.xcscheme_^#shared#^_ 28 | 29 | orderHint 30 | 0 31 | 32 | NotificationService.xcscheme_^#shared#^_ 33 | 34 | orderHint 35 | 5 36 | 37 | Preview.xcscheme_^#shared#^_ 38 | 39 | orderHint 40 | 7 41 | 42 | Share.xcscheme_^#shared#^_ 43 | 44 | orderHint 45 | 1 46 | 47 | Spotlight.xcscheme_^#shared#^_ 48 | 49 | orderHint 50 | 3 51 | 52 | iMessage.xcscheme_^#shared#^_ 53 | 54 | orderHint 55 | 4 56 | 57 | 58 | SuppressBuildableAutocreation 59 | 60 | 4E5F30612BC35E9000356231 61 | 62 | primary 63 | 64 | 65 | 4E5F30772BC35F3000356231 66 | 67 | primary 68 | 69 | 70 | 4E5F308F2BC35FAD00356231 71 | 72 | primary 73 | 74 | 75 | 4E5F30A12BC35FFF00356231 76 | 77 | primary 78 | 79 | 80 | 4E5F30B72BC3602400356231 81 | 82 | primary 83 | 84 | 85 | 4E5F30CD2BC3606300356231 86 | 87 | primary 88 | 89 | 90 | 4E5F30E42BC3659600356231 91 | 92 | primary 93 | 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /iMessage/Assets.xcassets/iMessage App Icon.stickersiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "icon-messages-settings-29x29@2x.png", 5 | "idiom" : "iphone", 6 | "scale" : "2x", 7 | "size" : "29x29" 8 | }, 9 | { 10 | "filename" : "icon-messages-settings-29x29@3x.png", 11 | "idiom" : "iphone", 12 | "scale" : "3x", 13 | "size" : "29x29" 14 | }, 15 | { 16 | "filename" : "icon-messages-app-iPhone-60x45@2x.png", 17 | "idiom" : "iphone", 18 | "scale" : "2x", 19 | "size" : "60x45" 20 | }, 21 | { 22 | "filename" : "icon-messages-app-iPhone-60x45@3x.png", 23 | "idiom" : "iphone", 24 | "scale" : "3x", 25 | "size" : "60x45" 26 | }, 27 | { 28 | "filename" : "icon-messages-settings-29x29@2x 1.png", 29 | "idiom" : "ipad", 30 | "scale" : "2x", 31 | "size" : "29x29" 32 | }, 33 | { 34 | "filename" : "icon-messages-app-iPadAir-67x50@2x.png", 35 | "idiom" : "ipad", 36 | "scale" : "2x", 37 | "size" : "67x50" 38 | }, 39 | { 40 | "filename" : "icon-messages-app-iPadAir-74x55@2x.png", 41 | "idiom" : "ipad", 42 | "scale" : "2x", 43 | "size" : "74x55" 44 | }, 45 | { 46 | "filename" : "icon-messages-app-store-1024x1024.png", 47 | "idiom" : "ios-marketing", 48 | "scale" : "1x", 49 | "size" : "1024x1024" 50 | }, 51 | { 52 | "filename" : "icon-messages-app-27x20@2x.png", 53 | "idiom" : "universal", 54 | "platform" : "ios", 55 | "scale" : "2x", 56 | "size" : "27x20" 57 | }, 58 | { 59 | "filename" : "icon-messages-app-27x20@3x.png", 60 | "idiom" : "universal", 61 | "platform" : "ios", 62 | "scale" : "3x", 63 | "size" : "27x20" 64 | }, 65 | { 66 | "filename" : "icon-messages-transcript-32x24@2x.png", 67 | "idiom" : "universal", 68 | "platform" : "ios", 69 | "scale" : "2x", 70 | "size" : "32x24" 71 | }, 72 | { 73 | "filename" : "icon-messages-transcript-32x24@3x.png", 74 | "idiom" : "universal", 75 | "platform" : "ios", 76 | "scale" : "3x", 77 | "size" : "32x24" 78 | }, 79 | { 80 | "filename" : "icon-messages-app-store-1024x768.png", 81 | "idiom" : "ios-marketing", 82 | "platform" : "ios", 83 | "scale" : "1x", 84 | "size" : "1024x768" 85 | } 86 | ], 87 | "info" : { 88 | "author" : "xcode", 89 | "version" : 1 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Share/ShareViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ShareViewController.swift 3 | // Share 4 | // 5 | // Created by Vince Davis on 4/7/24. 6 | // 7 | 8 | import Social 9 | import SwiftUI 10 | import HeroiOS 11 | import HeroShared 12 | 13 | #if os(iOS) 14 | import UIKit 15 | import MobileCoreServices 16 | import UniformTypeIdentifiers 17 | 18 | class ShareViewController: UIViewController { 19 | override func viewDidLoad() { 20 | super.viewDidLoad() 21 | 22 | var imageFound = false 23 | print("share started") 24 | for item in self.extensionContext!.inputItems as! [NSExtensionItem] { 25 | for provider in item.attachments! { 26 | print("share looping") 27 | if provider.hasItemConformingToTypeIdentifier(UTType.image.identifier) { 28 | // This is an image. We'll load it, then place it in our image view. 29 | provider.loadItem(forTypeIdentifier: UTType.image.identifier, options: nil, completionHandler: { (imageURL, error) in 30 | OperationQueue.main.addOperation { 31 | if let imageURL = imageURL as? URL { 32 | print("share found") 33 | let image = UIImage(data: try! Data(contentsOf: imageURL)) 34 | let shareView = ShareView(image: image, action: self.done) 35 | self.add(swiftUIView: AnyView(shareView)) 36 | } 37 | } 38 | }) 39 | 40 | imageFound = true 41 | break 42 | } 43 | } 44 | 45 | if (imageFound) { 46 | // We only handle one image, so stop looking for more. 47 | print("share donw") 48 | break 49 | } 50 | } 51 | } 52 | 53 | /// Close the Share Extension 54 | func done() { 55 | self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil) 56 | } 57 | } 58 | #endif 59 | 60 | #if os(macOS) 61 | import AppKit 62 | 63 | class ShareViewController: NSViewController { 64 | override func viewDidLoad() { 65 | super.viewDidLoad() 66 | 67 | self.add(swiftUIView: AnyView(SwiftUIView(action: close))) 68 | } 69 | 70 | /// Close the Share Extension 71 | func close() { 72 | self.extensionContext?.completeRequest(returningItems: [], completionHandler: nil) 73 | } 74 | } 75 | #endif 76 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/ExternalScreens/ExternalScreenControlView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExternalScreenControlView.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/15/24. 6 | // 7 | 8 | import SwiftUI 9 | import Observation 10 | 11 | struct ExternalScreenControlView: View { 12 | @Bindable var viewModel: ScreenManager 13 | 14 | var body: some View { 15 | ZStack { 16 | LinearGradient(gradient: Gradient(colors: [.heroOrange,.heroBlue]), startPoint: .top, endPoint: .bottom) 17 | 18 | HStack { 19 | Button(action: { 20 | viewModel.minus() 21 | }, label: { 22 | Image(systemName: "chevron.left") 23 | .font(.largeTitle) 24 | .foregroundStyle(viewModel.selection == 0 ? .gray : .white) 25 | .bold() 26 | }).disabled(viewModel.selection == 0) 27 | 28 | Spacer() 29 | 30 | speakerTabView 31 | 32 | Spacer() 33 | 34 | Button(action: { 35 | viewModel.add() 36 | }, label: { 37 | Image(systemName: "chevron.right") 38 | .font(.largeTitle) 39 | .foregroundStyle(viewModel.selection == (viewModel.speakers.count - 1) ? .gray : .white) 40 | .bold() 41 | }).disabled(viewModel.selection == (viewModel.speakers.count - 1)) 42 | } 43 | .padding() 44 | } 45 | .ignoresSafeArea() 46 | } 47 | 48 | @ViewBuilder 49 | var speakerTabView: some View { 50 | TabView(selection: $viewModel.selection) { 51 | ForEach(0.. Bool { 17 | 18 | print("AppDelegate first") 19 | UNUserNotificationCenter.current().delegate = self 20 | NotificationHelper().setup() 21 | application.registerForRemoteNotifications() 22 | 23 | return true 24 | } 25 | 26 | public func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { 27 | let tokenChars = (deviceToken as NSData).bytes.bindMemory(to: CChar.self, capacity: deviceToken.count) 28 | var tokenString = "" 29 | for i in 0.. Void) 16 | public init(image: UIImage? = nil, action: @escaping (() -> Void)) { 17 | self.image = image 18 | self.action = action 19 | } 20 | #elseif os(macOS) 21 | public var image: NSImage? 22 | public var action: (() -> Void) 23 | public init(image: NSImage? = nil, action: @escaping (() -> Void)) { 24 | self.image = image 25 | self.action = action 26 | } 27 | #else 28 | public var image: Image? 29 | public var action: (() -> Void) 30 | public init(image: Image? = nil, action: @escaping (() -> Void)) { 31 | self.image = image 32 | self.action = action 33 | } 34 | #endif 35 | 36 | public var body: some View { 37 | NavigationStack { 38 | ZStack { 39 | LinearGradient(gradient: Gradient(colors: [.heroOrange,.heroBlue ]), startPoint: .top, endPoint: .bottom) 40 | 41 | if let foundImage = image { 42 | #if os(iOS) 43 | let newImage = Image(uiImage: foundImage) 44 | #elseif os(macOS) 45 | let newImage = Image(nsImage: foundImage) 46 | #else 47 | let newImage = foundImage 48 | #endif 49 | VStack { 50 | HStack { 51 | Image.logo 52 | .resizable() 53 | .frame(width: 100, height: 100) 54 | .cornerRadius(15.0) 55 | 56 | Image.wordLogo 57 | .resizable() 58 | .frame(height: 150) 59 | } 60 | .padding() 61 | 62 | newImage.resizable().frame(width: 300, height: 300) 63 | Text("Found Image") 64 | } 65 | } else { 66 | VStack { 67 | Text("Bad Image") 68 | } 69 | } 70 | } 71 | .ignoresSafeArea() 72 | #if os(iOS) 73 | .toolbar { 74 | ToolbarItem(placement: .topBarTrailing, content: { 75 | Button(action: { 76 | action() 77 | }, label: { 78 | Image(systemName: "x.circle.fill") 79 | }) 80 | }) 81 | } 82 | #endif 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Spotlight/Spotlight.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/13/24. 6 | // 7 | 8 | #if os(iOS) || os(macOS) || os(visionOS) 9 | import UniformTypeIdentifiers 10 | import CoreSpotlight 11 | #endif 12 | #if os(iOS) 13 | import UIKit 14 | #endif 15 | 16 | public struct Spotlight { 17 | @MainActor 18 | static public func indexSpeakers() async -> Bool { 19 | await withCheckedContinuation { continuation in 20 | Spotlight.indexSpeakers(){ success in 21 | continuation.resume(returning: success) 22 | } 23 | } 24 | } 25 | 26 | static public func deIndexSpeakers() async -> Bool { 27 | await withCheckedContinuation { continuation in 28 | Spotlight.deIndexSpeakers(){ success in 29 | continuation.resume(returning: success) 30 | } 31 | } 32 | } 33 | 34 | // static public func handleUserActivity(_ userActivity: NSUserActivity) { 35 | // 36 | // } 37 | } 38 | 39 | private extension Spotlight { 40 | @MainActor 41 | static private func indexSpeakers(completion: @escaping (Bool) -> Void) { 42 | #if os(iOS) || os(macOS) || os(visionOS) 43 | 44 | let items = Speaker.all.map({ 45 | let attributeSet = CSSearchableItemAttributeSet(contentType: UTType.text) 46 | attributeSet.title = $0.name 47 | attributeSet.contentDescription = $0.subtitle 48 | #if os(iOS) 49 | if let image = $0.image.getUIImage(newSize: .init(width: 30, height: 30)), 50 | let data = image.jpegData(compressionQuality: 1.0) { 51 | attributeSet.thumbnailData = data 52 | } 53 | attributeSet.actionIdentifiers = ["CS_ACTION_1"] 54 | #endif 55 | 56 | return CSSearchableItem(uniqueIdentifier: $0.id, domainIdentifier: "com.swiftheroes", attributeSet: attributeSet) 57 | }) 58 | 59 | CSSearchableIndex.default().indexSearchableItems(items) { error in 60 | if let error = error { 61 | print("Indexing error: \(error.localizedDescription)") 62 | completion(false) 63 | } else { 64 | print("Search item successfully indexed!") 65 | completion(true) 66 | } 67 | } 68 | #endif 69 | } 70 | 71 | static private func deIndexSpeakers(completion: @escaping (Bool) -> Void) { 72 | #if os(iOS) || os(macOS) || os(visionOS) 73 | let identifiers = Speaker.all.map({ $0.id }) 74 | CSSearchableIndex.default().deleteSearchableItems(withIdentifiers: identifiers) { error in 75 | if let error = error { 76 | print("Deindexing error: \(error.localizedDescription)") 77 | completion(false) 78 | } else { 79 | print("Search item successfully removed!") 80 | completion(true) 81 | } 82 | } 83 | #endif 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/Demo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 25 | 26 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /HeroesWatch Watch App/HeroesWatchApp.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HeroesWatchApp.swift 3 | // HeroesWatch Watch App 4 | // 5 | // Created by Vince Davis on 4/11/24. 6 | // 7 | 8 | import SwiftUI 9 | import HeroShared 10 | import UserNotifications 11 | 12 | import AVKit 13 | import Foundation 14 | 15 | @main 16 | struct HeroesWatch_Watch_AppApp: App { 17 | //@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate 18 | 19 | var body: some Scene { 20 | WindowGroup { 21 | ContentView() 22 | } 23 | 24 | WKNotificationScene(controller: NotificationController.self, category: "video") 25 | } 26 | } 27 | 28 | import AVFoundation 29 | struct NotificationView: View { 30 | var speaker: Speaker = .alex 31 | @State var isSwitched: Bool = false 32 | public var player: AVPlayer = AVPlayer(url: Bundle.main.url(forResource: "highlights", withExtension: "mp4")!) 33 | 34 | var body: some View { 35 | VStack { 36 | // speaker.image 37 | // .resizable() 38 | // .scaledToFit() 39 | // .cornerRadius(5.0) 40 | VideoPlayer(player: player).scaledToFit() 41 | 42 | Text(speaker.name) 43 | .font(.headline) 44 | 45 | //Toggle("Test Me", isOn: $isSwitched) 46 | Button("Play", action: { player.play() }) 47 | 48 | Divider() 49 | 50 | if isSwitched { 51 | Text("You are within 5 miles of one of your favorite landmarks.") 52 | .font(.caption) 53 | } 54 | } 55 | } 56 | } 57 | 58 | 59 | #Preview { 60 | NotificationView() 61 | } 62 | 63 | class NotificationController: WKUserNotificationHostingController { 64 | 65 | let landmarkIndexKey = "landmarkIndex" 66 | 67 | override var body: NotificationView { 68 | NotificationView(speaker: .alberto) 69 | 70 | } 71 | 72 | override class var isInteractive: Bool { 73 | return true 74 | } 75 | 76 | override class var sashColor: Color? { 77 | return Color.heroBlue 78 | } 79 | 80 | override class var wantsSashBlur: Bool { 81 | return true 82 | } 83 | 84 | override class var titleColor: Color? { 85 | return .heroOrange 86 | } 87 | 88 | override class var subtitleColor: Color? { 89 | return .secondary 90 | } 91 | 92 | override func didReceive(_ notification: UNNotification) { 93 | //let modelData = ModelData() 94 | self.notificationActions = [.init(identifier: "action_identifier", title: "Dynamic action title")] 95 | let notificationData = 96 | notification.request.content.userInfo as? [String: Any] 97 | 98 | // let aps = notificationData?["aps"] as? [String: Any] 99 | // let alert = aps?["alert"] as? [String: Any] 100 | // 101 | // 102 | // title = alert?["title"] as? String 103 | // message = alert?["body"] as? String 104 | // 105 | // 106 | // if let index = notificationData?[landmarkIndexKey] as? Int { 107 | // landmark = modelData.landmarks[index] 108 | // } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Extensions/Image+Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Image.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/8/24. 6 | // 7 | 8 | import SwiftUI 9 | 10 | public extension Image { 11 | static let alberto = Image("alberto", bundle: .module) 12 | static let alex = Image("alex", bundle: .module) 13 | static let andrea = Image("andrea", bundle: .module) 14 | static let andrei = Image("andrei", bundle: .module) 15 | static let batuhan = Image("batuhan", bundle: .module) 16 | static let beyza = Image("beyza", bundle: .module) 17 | static let borbala = Image("borbala", bundle: .module) 18 | static let brad = Image("brad", bundle: .module) 19 | static let davide = Image("davide", bundle: .module) 20 | static let davide2 = Image("davide2", bundle: .module) 21 | static let emilio = Image("emilio", bundle: .module) 22 | static let flora = Image("flora", bundle: .module) 23 | static let gyuree = Image("gyuree", bundle: .module) 24 | static let jane = Image("jane", bundle: .module) 25 | static let josip = Image("josip", bundle: .module) 26 | static let krysztof = Image("krysztof", bundle: .module) 27 | static let libranner = Image("libranner", bundle: .module) 28 | static let lukasz = Image("lukasz", bundle: .module) 29 | static let marcin = Image("marcin", bundle: .module) 30 | static let marco = Image("marco", bundle: .module) 31 | static let mete = Image("mete", bundle: .module) 32 | static let michael = Image("michael", bundle: .module) 33 | static let natan = Image("natan", bundle: .module) 34 | static let pedro = Image("pedro", bundle: .module) 35 | static let peter = Image("peter", bundle: .module) 36 | static let pietro = Image("pietro", bundle: .module) 37 | static let pol = Image("pol", bundle: .module) 38 | static let pradnya = Image("pradnya", bundle: .module) 39 | static let sara = Image("sara", bundle: .module) 40 | static let shai = Image("shai", bundle: .module) 41 | static let stefano = Image("stefano", bundle: .module) 42 | static let vince = Image("vince", bundle: .module) 43 | static let vincenzo = Image("vincenzo", bundle: .module) 44 | static let zach = Image("zach", bundle: .module) 45 | 46 | static let logo = Image("logo", bundle: .module) 47 | static let wordLogo = Image("wordLogo", bundle: .module) 48 | 49 | static let ios3 = Image("ios3", bundle: .module) 50 | static let ios4 = Image("ios4", bundle: .module) 51 | static let ios8 = Image("ios8", bundle: .module) 52 | static let ios9 = Image("ios9", bundle: .module) 53 | static let ios10 = Image("ios10", bundle: .module) 54 | static let ios14 = Image("ios14", bundle: .module) 55 | } 56 | 57 | public extension Image { 58 | func styled() -> some View { 59 | self 60 | .font(.title2) 61 | .symbolRenderingMode(.palette) 62 | .foregroundStyle(Color.heroOrange, Color.heroBlue) 63 | } 64 | #if os(iOS) 65 | @MainActor 66 | func getUIImage(newSize: CGSize) -> UIImage? { 67 | let image = resizable() 68 | .scaledToFill() 69 | .frame(width: newSize.width, height: newSize.height) 70 | .clipped() 71 | return ImageRenderer(content: image).uiImage 72 | } 73 | #endif 74 | } 75 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Views/SpeakerListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SpeakerListView.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/9/24. 6 | // 7 | 8 | import SwiftUI 9 | import Observation 10 | import HeroShared 11 | 12 | let activityType = "com.swiftheroes.speakers" 13 | 14 | public struct SpeakerListView: View { 15 | @Environment(ScreenManager.self) var screenManager: ScreenManager 16 | 17 | @State var quickActionsManager = QuickActionsManager.shared 18 | @State private var isSheetPresented = false 19 | 20 | public init() {} 21 | 22 | let columns = [ 23 | GridItem(.flexible()), 24 | GridItem(.flexible()), 25 | ] 26 | 27 | public var body: some View { 28 | NavigationStack { 29 | ScrollView { 30 | LazyVGrid(columns: columns, spacing: 20) { 31 | ForEach(Speaker.all, id: \.id) { speaker in 32 | VStack { 33 | speaker.image 34 | .resizable() 35 | .frame(width: 150, height: 150) 36 | .cornerRadius(15.0) 37 | 38 | Text(speaker.title) 39 | .font(.title3) 40 | .bold() 41 | } 42 | } 43 | } 44 | .padding(.horizontal) 45 | } 46 | .padding() 47 | .navigationTitle("Speakers") 48 | .customToolBarStyle() 49 | .externalScreenToolbar(screenManager: screenManager, showingSheet: $isSheetPresented) 50 | } 51 | .sheet(isPresented: $isSheetPresented) { 52 | Text("Half screen content here") 53 | .presentationDetents([.fraction(0.33), .medium]) 54 | //.interactiveDismissDisabled(true) 55 | } 56 | .userActivity(activityType, element: "1", { element, activity in 57 | let bundleid = Bundle.main.bundleIdentifier ?? "" 58 | 59 | activity.addUserInfoEntries(from: ["id": "1", 60 | "name": "Alex", 61 | "setby": bundleid]) 62 | //activity.el 63 | logUserActivity(activity, label: "Activity") 64 | }) 65 | .onContinueUserActivity(activityType, perform: { userActivity in 66 | if let _ = userActivity.userInfo?["id"] as? String { 67 | // Load handoff page 68 | 69 | } 70 | 71 | logUserActivity(userActivity, label: "on activity") 72 | }) 73 | .onChange(of: quickActionsManager.quickAction) { _, _ in 74 | print("Change current action is \(String(describing: quickActionsManager.quickAction?.rawValue))") 75 | } 76 | .onChange(of: screenManager.showScreen) { _, newValue in 77 | isSheetPresented = newValue 78 | } 79 | .onAppear { 80 | print("current action is \(String(describing: quickActionsManager.quickAction?.rawValue))") 81 | } 82 | } 83 | 84 | func logUserActivity(_ activity: NSUserActivity, label: String = "") { 85 | print("\(label) TYPE = \(activity.activityType)") 86 | print("\(label) INFO = \(activity.userInfo ?? [:])") 87 | } 88 | } 89 | 90 | #Preview { 91 | SpeakerListView() 92 | #if os(iOS) 93 | .environment(ScreenManager()) 94 | #endif 95 | } 96 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroiOS/Views/ExtensionListView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionListView 2.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import SwiftUI 9 | import HeroShared 10 | 11 | public struct ExtensionListView: View { 12 | @Environment(ScreenManager.self) var screenManager: ScreenManager 13 | @State var quickActionsManager = QuickActionsManager.shared 14 | @State private var isSheetPresented = false 15 | 16 | public init() {} 17 | 18 | public var body: some View { 19 | NavigationStack { 20 | List(ExtensionItem.all) { item in 21 | HStack { 22 | Label(title: { 23 | Text(item.name) 24 | }, icon: { 25 | item.image.styled() 26 | }) 27 | Spacer() 28 | 29 | ZStack { 30 | Rectangle() 31 | .foregroundColor(Color.heroOrange.opacity(0.3)) 32 | .cornerRadius(10) 33 | 34 | 35 | HStack(spacing: 2) { 36 | Image(systemName: "iphone") 37 | Image(systemName: "applewatch") 38 | Image(systemName: "ipad") 39 | Image(systemName: "macbook") 40 | Image(systemName: "appletv") 41 | Image(systemName: "visionpro") 42 | } 43 | } 44 | .frame(width: 150, height: 30) 45 | } 46 | } 47 | .customListStyle() 48 | .navigationTitle("Extensions") 49 | .customToolBarStyle() 50 | .externalScreenToolbar(screenManager: screenManager, showingSheet: $isSheetPresented) 51 | } 52 | .sheet(isPresented: $isSheetPresented) { 53 | Text("Half screen content here") 54 | .presentationDetents([.fraction(0.33), .medium]) 55 | } 56 | .userActivity(activityType, element: "1", { element, activity in 57 | let bundleid = Bundle.main.bundleIdentifier ?? "" 58 | 59 | activity.addUserInfoEntries(from: ["id": "1", 60 | "name": "Alex", 61 | "setby": bundleid]) 62 | //activity.el 63 | logUserActivity(activity, label: "Activity") 64 | }) 65 | .onContinueUserActivity(activityType, perform: { userActivity in 66 | if let _ = userActivity.userInfo?["id"] as? String { 67 | // Load handoff page 68 | 69 | } 70 | 71 | logUserActivity(userActivity, label: "on activity") 72 | }) 73 | .onChange(of: quickActionsManager.quickAction) { _, _ in 74 | print("Change current action is \(String(describing: quickActionsManager.quickAction?.rawValue))") 75 | } 76 | .onChange(of: screenManager.showScreen) { _, newValue in 77 | isSheetPresented = newValue 78 | } 79 | .onAppear { 80 | print("current action is \(String(describing: quickActionsManager.quickAction?.rawValue))") 81 | } 82 | } 83 | 84 | func logUserActivity(_ activity: NSUserActivity, label: String = "") { 85 | print("\(label) TYPE = \(activity.activityType)") 86 | print("\(label) INFO = \(activity.userInfo ?? [:])") 87 | } 88 | } 89 | 90 | #Preview { 91 | ExtensionListView() 92 | .environment(ScreenManager()) 93 | } 94 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Data/ExtensionItem.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ExtensionItem.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import Foundation 9 | import SwiftUI 10 | 11 | public struct ExtensionItem: Identifiable, Equatable { 12 | public init(id: String, name: String, desc: String, image: Image, platforms: [String]) { 13 | self.id = id 14 | self.name = name 15 | self.desc = desc 16 | self.image = image 17 | self.platforms = platforms 18 | } 19 | 20 | public var id: String 21 | public var name: String 22 | public var desc: String 23 | public var image: Image 24 | public var platforms: [String] 25 | } 26 | 27 | public extension ExtensionItem { 28 | static var all: [ExtensionItem] { 29 | return [ 30 | .init(id: "100", 31 | name: "Action", 32 | desc: "", 33 | image: Image(systemName: "bolt.fill"), 34 | platforms: [.iphone, .ipad, .mac] 35 | ), 36 | .init(id: "200", 37 | name: "Share", 38 | desc: "", 39 | image: Image(systemName: "square.and.arrow.up"), 40 | platforms: [.iphone, .ipad, .mac] 41 | ), 42 | .init(id: "300", 43 | name: "Notification", 44 | desc: "", 45 | image: Image(systemName: "bell.badge.fill"), 46 | platforms: [.iphone, .watch, .ipad, .mac, .xr] 47 | ), 48 | .init(id: "400", 49 | name: "iMessage", 50 | desc: "", 51 | image: Image(systemName: "message.fill"), 52 | platforms: [.iphone, .ipad] 53 | ), 54 | .init(id: "500", 55 | name: "Spotlight", 56 | desc: "", 57 | image: Image(systemName: "magnifyingglass"), 58 | platforms: [.iphone, .ipad, .mac] 59 | ), 60 | .init(id: "600", 61 | name: "AppClips", 62 | desc: "", 63 | image: Image(systemName: "appclip"), 64 | platforms: [.iphone, .ipad] 65 | ), 66 | .init(id: "700", 67 | name: "Quick Actions", 68 | desc: "", 69 | image: Image(systemName: "list.bullet"), 70 | platforms: [.iphone, .ipad] 71 | ), 72 | .init(id: "800", 73 | name: "Handoff", 74 | desc: "", 75 | image: Image(systemName: "macbook.and.iphone"), 76 | platforms: [.iphone, .watch, .ipad, .mac, .tv, .xr] 77 | ), 78 | .init(id: "900", 79 | name: "External Screen", 80 | desc: "", 81 | image: Image(systemName: "tv"), 82 | platforms: [.iphone, .ipad] 83 | ), 84 | .init(id: "950", 85 | name: "Quick Look Preview", 86 | desc: "", 87 | image: Image(systemName: "eye.fill"), 88 | platforms: [.iphone, .ipad] 89 | ), 90 | ] 91 | } 92 | } 93 | 94 | extension ExtensionItem: Listable { 95 | public var type: ListType { 96 | return .extensionItem 97 | } 98 | 99 | public var title: String { 100 | self.name 101 | } 102 | 103 | public var subtitle: String { 104 | self.desc 105 | } 106 | 107 | public var badges: [String] { 108 | self.platforms 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/Action.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 59 | 61 | 67 | 68 | 69 | 70 | 78 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/iMessage.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 59 | 61 | 67 | 68 | 69 | 70 | 78 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/Spotlight.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 59 | 61 | 67 | 68 | 69 | 70 | 78 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/Notification.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 59 | 61 | 67 | 68 | 69 | 70 | 78 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/NotificationService.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 9 | 10 | 16 | 22 | 23 | 24 | 30 | 36 | 37 | 38 | 39 | 40 | 46 | 47 | 59 | 61 | 67 | 68 | 69 | 70 | 78 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /Demo.xcodeproj/xcshareddata/xcschemes/Share.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 6 | 10 | 11 | 17 | 23 | 24 | 25 | 31 | 37 | 38 | 39 | 40 | 41 | 47 | 48 | 60 | 62 | 68 | 69 | 70 | 71 | 79 | 81 | 87 | 88 | 89 | 90 | 92 | 93 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /Heroes/Sources/HeroShared/Notifications/NotificationHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NotificationHelper.swift 3 | // 4 | // 5 | // Created by Vince Davis on 4/10/24. 6 | // 7 | 8 | import Foundation 9 | #if !os(tvOS) 10 | import UserNotifications 11 | 12 | public struct NotificationHelper { 13 | public init() {} 14 | public func setup() { 15 | let changeAction = UNNotificationAction(identifier: "testNotification.changeAction", 16 | title: "Change Rating", 17 | options: [], 18 | icon: .init(systemImageName: "star.fill")) 19 | let submitAction = UNNotificationAction(identifier: "testNotification.submitAction", 20 | title: "Submit", 21 | options: [.destructive], 22 | icon: .init(systemImageName: "paperplane.fill")) 23 | let testNotifCategory = UNNotificationCategory(identifier: "default", 24 | actions: [changeAction, submitAction], 25 | intentIdentifiers: [], 26 | options: []) 27 | 28 | let playAction = UNNotificationAction(identifier: "testNotification.playAction", 29 | title: "Play", 30 | options: [], 31 | icon: .init(systemImageName: "play.fill")) 32 | let pauseAction = UNNotificationAction(identifier: "testNotification.pauseAction", 33 | title: "Pause", 34 | options: [], 35 | icon: .init(systemImageName: "pause.fill")) 36 | let videoNotifCategory = UNNotificationCategory(identifier: "video", 37 | actions: [playAction, pauseAction], 38 | intentIdentifiers: [], 39 | options: []) 40 | 41 | let action = UNNotificationAction(identifier: "testNotification.slideAction", 42 | title: "Slide", 43 | options: [], 44 | icon: .init(systemImageName: "photo.artframe")) 45 | 46 | let imageNotifCategory = UNNotificationCategory(identifier: "images", 47 | actions: [action], 48 | intentIdentifiers: [], 49 | options: []) 50 | 51 | let statusAction = UNNotificationAction(identifier: "testNotification.showFlight", 52 | title: "Show Flight Status", 53 | options: [], 54 | icon: .init(systemImageName: "airplane")) 55 | 56 | let statusNotifCategory = UNNotificationCategory(identifier: "flightStatus", 57 | actions: [statusAction], 58 | intentIdentifiers: [], 59 | options: []) 60 | 61 | UNUserNotificationCenter.current().setNotificationCategories([testNotifCategory,imageNotifCategory,videoNotifCategory, statusNotifCategory]) 62 | 63 | 64 | let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] 65 | UNUserNotificationCenter.current().requestAuthorization( 66 | options: authOptions, 67 | completionHandler: {_, _ in }) 68 | } 69 | } 70 | #endif 71 | --------------------------------------------------------------------------------