commit b545a3bc0546ee4b06d66f8396a7f80fdf3b70a0 Author: Shadowfacts Date: Sun Sep 25 11:42:45 2022 -0400 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fc6431b --- /dev/null +++ b/.gitignore @@ -0,0 +1,78 @@ +.DS_Store +MyPlayground.playground/ + +### Swift ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +.build/ + +# CocoaPods - Refactored to standalone file + +# Carthage - Refactored to standalone file + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated + +## Various settings + +## Other + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno diff --git a/BadWidgets/Assets.xcassets/AccentColor.colorset/Contents.json b/BadWidgets/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/BadWidgets/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BadWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json b/BadWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/BadWidgets/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BadWidgets/Assets.xcassets/Contents.json b/BadWidgets/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/BadWidgets/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BadWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json b/BadWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/BadWidgets/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BadWidgets/BadWidgets.swift b/BadWidgets/BadWidgets.swift new file mode 100644 index 0000000..5bffea1 --- /dev/null +++ b/BadWidgets/BadWidgets.swift @@ -0,0 +1,32 @@ +// +// BadWidgets.swift +// BadWidgets +// +// Created by Shadowfacts on 9/24/22. +// + +import WidgetKit +import SwiftUI + +@main +struct BadWidgets: Widget { + let kind: String = "BadWidgets" + + var body: some WidgetConfiguration { + ActivityConfiguration(for: BadAppleAttributes.self) { context in + FrameView(frame: context.state.frame) + } dynamicIsland: { context in + DynamicIsland { + DynamicIslandExpandedRegion(.leading) { + FrameView(frame: context.state.frame) + } + } compactLeading: { + FrameView(frame: context.state.frame) + } compactTrailing: { + } minimal: { + FrameView(frame: context.state.frame) + } + } + + } +} diff --git a/BadWidgets/Info.plist b/BadWidgets/Info.plist new file mode 100644 index 0000000..0f118fb --- /dev/null +++ b/BadWidgets/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/LiveApple.xcodeproj/project.pbxproj b/LiveApple.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d856a6d --- /dev/null +++ b/LiveApple.xcodeproj/project.pbxproj @@ -0,0 +1,578 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + D6F4AA6428DF6D890086EC06 /* LiveAppleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA6328DF6D890086EC06 /* LiveAppleApp.swift */; }; + D6F4AA6628DF6D890086EC06 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA6528DF6D890086EC06 /* ContentView.swift */; }; + D6F4AA6828DF6D8A0086EC06 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6F4AA6728DF6D8A0086EC06 /* Assets.xcassets */; }; + D6F4AA6B28DF6D8A0086EC06 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6F4AA6A28DF6D8A0086EC06 /* Preview Assets.xcassets */; }; + D6F4AA7228DF6DA80086EC06 /* PlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA7128DF6DA80086EC06 /* PlayerView.swift */; }; + D6F4AA7428DF6DC00086EC06 /* PlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA7328DF6DC00086EC06 /* PlayerController.swift */; }; + D6F4AA7628DF6ED70086EC06 /* badapple.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = D6F4AA7528DF6E8B0086EC06 /* badapple.mp4 */; }; + D6F4AA7E28DF6F3C0086EC06 /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6F4AA7D28DF6F3C0086EC06 /* WidgetKit.framework */; }; + D6F4AA8028DF6F3C0086EC06 /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D6F4AA7F28DF6F3C0086EC06 /* SwiftUI.framework */; }; + D6F4AA8328DF6F3C0086EC06 /* BadWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA8228DF6F3C0086EC06 /* BadWidgets.swift */; }; + D6F4AA8528DF6F3D0086EC06 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D6F4AA8428DF6F3D0086EC06 /* Assets.xcassets */; }; + D6F4AA8928DF6F3D0086EC06 /* BadWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = D6F4AA7B28DF6F3C0086EC06 /* BadWidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + D6F4AA9028DF6F870086EC06 /* Activities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA8F28DF6F870086EC06 /* Activities.swift */; }; + D6F4AA9228DF70450086EC06 /* Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9128DF70450086EC06 /* Frame.swift */; }; + D6F4AA9428DF95960086EC06 /* FrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9328DF95960086EC06 /* FrameView.swift */; }; + D6F4AA9528DFC2F50086EC06 /* Activities.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA8F28DF6F870086EC06 /* Activities.swift */; }; + D6F4AA9628DFC31C0086EC06 /* FrameView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9328DF95960086EC06 /* FrameView.swift */; }; + D6F4AA9828DFC3D70086EC06 /* Frame+CV.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9728DFC3D70086EC06 /* Frame+CV.swift */; }; + D6F4AA9928DFC3F80086EC06 /* Frame.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9128DF70450086EC06 /* Frame.swift */; }; + D6F4AA9B28DFC8EF0086EC06 /* BackgroundManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6F4AA9A28DFC8EF0086EC06 /* BackgroundManager.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + D6F4AA8728DF6F3D0086EC06 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = D6F4AA5828DF6D890086EC06 /* Project object */; + proxyType = 1; + remoteGlobalIDString = D6F4AA7A28DF6F3C0086EC06; + remoteInfo = BadWidgetsExtension; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + D6F4AA8D28DF6F3D0086EC06 /* Embed Foundation Extensions */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 13; + files = ( + D6F4AA8928DF6F3D0086EC06 /* BadWidgetsExtension.appex in Embed Foundation Extensions */, + ); + name = "Embed Foundation Extensions"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D6F4AA6028DF6D890086EC06 /* LiveApple.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = LiveApple.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D6F4AA6328DF6D890086EC06 /* LiveAppleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveAppleApp.swift; sourceTree = ""; }; + D6F4AA6528DF6D890086EC06 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + D6F4AA6728DF6D8A0086EC06 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D6F4AA6A28DF6D8A0086EC06 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + D6F4AA7128DF6DA80086EC06 /* PlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerView.swift; sourceTree = ""; }; + D6F4AA7328DF6DC00086EC06 /* PlayerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerController.swift; sourceTree = ""; }; + D6F4AA7528DF6E8B0086EC06 /* badapple.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = badapple.mp4; sourceTree = ""; }; + D6F4AA7B28DF6F3C0086EC06 /* BadWidgetsExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = BadWidgetsExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + D6F4AA7D28DF6F3C0086EC06 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; + D6F4AA7F28DF6F3C0086EC06 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; + D6F4AA8228DF6F3C0086EC06 /* BadWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadWidgets.swift; sourceTree = ""; }; + D6F4AA8428DF6F3D0086EC06 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D6F4AA8628DF6F3D0086EC06 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D6F4AA8E28DF6F600086EC06 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + D6F4AA8F28DF6F870086EC06 /* Activities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Activities.swift; sourceTree = ""; }; + D6F4AA9128DF70450086EC06 /* Frame.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Frame.swift; sourceTree = ""; }; + D6F4AA9328DF95960086EC06 /* FrameView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FrameView.swift; sourceTree = ""; }; + D6F4AA9728DFC3D70086EC06 /* Frame+CV.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Frame+CV.swift"; sourceTree = ""; }; + D6F4AA9A28DFC8EF0086EC06 /* BackgroundManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundManager.swift; sourceTree = ""; }; + D6F4AA9C28DFEAC70086EC06 /* LiveApple.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = LiveApple.entitlements; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D6F4AA5D28DF6D890086EC06 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D6F4AA7828DF6F3C0086EC06 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D6F4AA8028DF6F3C0086EC06 /* SwiftUI.framework in Frameworks */, + D6F4AA7E28DF6F3C0086EC06 /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D6F4AA5728DF6D890086EC06 = { + isa = PBXGroup; + children = ( + D6F4AA6228DF6D890086EC06 /* LiveApple */, + D6F4AA8128DF6F3C0086EC06 /* BadWidgets */, + D6F4AA7C28DF6F3C0086EC06 /* Frameworks */, + D6F4AA6128DF6D890086EC06 /* Products */, + ); + sourceTree = ""; + }; + D6F4AA6128DF6D890086EC06 /* Products */ = { + isa = PBXGroup; + children = ( + D6F4AA6028DF6D890086EC06 /* LiveApple.app */, + D6F4AA7B28DF6F3C0086EC06 /* BadWidgetsExtension.appex */, + ); + name = Products; + sourceTree = ""; + }; + D6F4AA6228DF6D890086EC06 /* LiveApple */ = { + isa = PBXGroup; + children = ( + D6F4AA9C28DFEAC70086EC06 /* LiveApple.entitlements */, + D6F4AA8E28DF6F600086EC06 /* Info.plist */, + D6F4AA6328DF6D890086EC06 /* LiveAppleApp.swift */, + D6F4AA6528DF6D890086EC06 /* ContentView.swift */, + D6F4AA7328DF6DC00086EC06 /* PlayerController.swift */, + D6F4AA7128DF6DA80086EC06 /* PlayerView.swift */, + D6F4AA8F28DF6F870086EC06 /* Activities.swift */, + D6F4AA9128DF70450086EC06 /* Frame.swift */, + D6F4AA9728DFC3D70086EC06 /* Frame+CV.swift */, + D6F4AA9328DF95960086EC06 /* FrameView.swift */, + D6F4AA9A28DFC8EF0086EC06 /* BackgroundManager.swift */, + D6F4AA6728DF6D8A0086EC06 /* Assets.xcassets */, + D6F4AA7528DF6E8B0086EC06 /* badapple.mp4 */, + D6F4AA6928DF6D8A0086EC06 /* Preview Content */, + ); + path = LiveApple; + sourceTree = ""; + }; + D6F4AA6928DF6D8A0086EC06 /* Preview Content */ = { + isa = PBXGroup; + children = ( + D6F4AA6A28DF6D8A0086EC06 /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + D6F4AA7C28DF6F3C0086EC06 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D6F4AA7D28DF6F3C0086EC06 /* WidgetKit.framework */, + D6F4AA7F28DF6F3C0086EC06 /* SwiftUI.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + D6F4AA8128DF6F3C0086EC06 /* BadWidgets */ = { + isa = PBXGroup; + children = ( + D6F4AA8228DF6F3C0086EC06 /* BadWidgets.swift */, + D6F4AA8428DF6F3D0086EC06 /* Assets.xcassets */, + D6F4AA8628DF6F3D0086EC06 /* Info.plist */, + ); + path = BadWidgets; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D6F4AA5F28DF6D890086EC06 /* LiveApple */ = { + isa = PBXNativeTarget; + buildConfigurationList = D6F4AA6E28DF6D8A0086EC06 /* Build configuration list for PBXNativeTarget "LiveApple" */; + buildPhases = ( + D6F4AA5C28DF6D890086EC06 /* Sources */, + D6F4AA5D28DF6D890086EC06 /* Frameworks */, + D6F4AA5E28DF6D890086EC06 /* Resources */, + D6F4AA8D28DF6F3D0086EC06 /* Embed Foundation Extensions */, + ); + buildRules = ( + ); + dependencies = ( + D6F4AA8828DF6F3D0086EC06 /* PBXTargetDependency */, + ); + name = LiveApple; + productName = LiveApple; + productReference = D6F4AA6028DF6D890086EC06 /* LiveApple.app */; + productType = "com.apple.product-type.application"; + }; + D6F4AA7A28DF6F3C0086EC06 /* BadWidgetsExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = D6F4AA8A28DF6F3D0086EC06 /* Build configuration list for PBXNativeTarget "BadWidgetsExtension" */; + buildPhases = ( + D6F4AA7728DF6F3C0086EC06 /* Sources */, + D6F4AA7828DF6F3C0086EC06 /* Frameworks */, + D6F4AA7928DF6F3C0086EC06 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = BadWidgetsExtension; + productName = BadWidgetsExtension; + productReference = D6F4AA7B28DF6F3C0086EC06 /* BadWidgetsExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D6F4AA5828DF6D890086EC06 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1410; + LastUpgradeCheck = 1410; + TargetAttributes = { + D6F4AA5F28DF6D890086EC06 = { + CreatedOnToolsVersion = 14.1; + }; + D6F4AA7A28DF6F3C0086EC06 = { + CreatedOnToolsVersion = 14.1; + }; + }; + }; + buildConfigurationList = D6F4AA5B28DF6D890086EC06 /* Build configuration list for PBXProject "LiveApple" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = D6F4AA5728DF6D890086EC06; + productRefGroup = D6F4AA6128DF6D890086EC06 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D6F4AA5F28DF6D890086EC06 /* LiveApple */, + D6F4AA7A28DF6F3C0086EC06 /* BadWidgetsExtension */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D6F4AA5E28DF6D890086EC06 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6F4AA6B28DF6D8A0086EC06 /* Preview Assets.xcassets in Resources */, + D6F4AA7628DF6ED70086EC06 /* badapple.mp4 in Resources */, + D6F4AA6828DF6D8A0086EC06 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D6F4AA7928DF6F3C0086EC06 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6F4AA8528DF6F3D0086EC06 /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D6F4AA5C28DF6D890086EC06 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6F4AA9828DFC3D70086EC06 /* Frame+CV.swift in Sources */, + D6F4AA7228DF6DA80086EC06 /* PlayerView.swift in Sources */, + D6F4AA6628DF6D890086EC06 /* ContentView.swift in Sources */, + D6F4AA7428DF6DC00086EC06 /* PlayerController.swift in Sources */, + D6F4AA9228DF70450086EC06 /* Frame.swift in Sources */, + D6F4AA9028DF6F870086EC06 /* Activities.swift in Sources */, + D6F4AA9B28DFC8EF0086EC06 /* BackgroundManager.swift in Sources */, + D6F4AA6428DF6D890086EC06 /* LiveAppleApp.swift in Sources */, + D6F4AA9428DF95960086EC06 /* FrameView.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D6F4AA7728DF6F3C0086EC06 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D6F4AA9628DFC31C0086EC06 /* FrameView.swift in Sources */, + D6F4AA9928DFC3F80086EC06 /* Frame.swift in Sources */, + D6F4AA9528DFC2F50086EC06 /* Activities.swift in Sources */, + D6F4AA8328DF6F3C0086EC06 /* BadWidgets.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + D6F4AA8828DF6F3D0086EC06 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = D6F4AA7A28DF6F3C0086EC06 /* BadWidgetsExtension */; + targetProxy = D6F4AA8728DF6F3D0086EC06 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + D6F4AA6C28DF6D8A0086EC06 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D6F4AA6D28DF6D8A0086EC06 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + D6F4AA6F28DF6D8A0086EC06 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = LiveApple/LiveApple.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"LiveApple/Preview Content\""; + DEVELOPMENT_TEAM = HGYVAQA9FW; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = LiveApple/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = hacks; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = because; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.LiveApple; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D6F4AA7028DF6D8A0086EC06 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_ENTITLEMENTS = LiveApple/LiveApple.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"LiveApple/Preview Content\""; + DEVELOPMENT_TEAM = HGYVAQA9FW; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = LiveApple/Info.plist; + INFOPLIST_KEY_NSLocationAlwaysAndWhenInUseUsageDescription = hacks; + INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = because; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + IPHONEOS_DEPLOYMENT_TARGET = 16.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.LiveApple; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; + D6F4AA8B28DF6F3D0086EC06 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HGYVAQA9FW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BadWidgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = BadWidgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.LiveApple.BadWidgets; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + D6F4AA8C28DF6F3D0086EC06 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = HGYVAQA9FW; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = BadWidgets/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = BadWidgets; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.LiveApple.BadWidgets; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D6F4AA5B28DF6D890086EC06 /* Build configuration list for PBXProject "LiveApple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6F4AA6C28DF6D8A0086EC06 /* Debug */, + D6F4AA6D28DF6D8A0086EC06 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D6F4AA6E28DF6D8A0086EC06 /* Build configuration list for PBXNativeTarget "LiveApple" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6F4AA6F28DF6D8A0086EC06 /* Debug */, + D6F4AA7028DF6D8A0086EC06 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D6F4AA8A28DF6F3D0086EC06 /* Build configuration list for PBXNativeTarget "BadWidgetsExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6F4AA8B28DF6F3D0086EC06 /* Debug */, + D6F4AA8C28DF6F3D0086EC06 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D6F4AA5828DF6D890086EC06 /* Project object */; +} diff --git a/LiveApple.xcodeproj/xcshareddata/xcschemes/BadWidgetsExtension.xcscheme b/LiveApple.xcodeproj/xcshareddata/xcschemes/BadWidgetsExtension.xcscheme new file mode 100644 index 0000000..732fb59 --- /dev/null +++ b/LiveApple.xcodeproj/xcshareddata/xcschemes/BadWidgetsExtension.xcscheme @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LiveApple.xcodeproj/xcshareddata/xcschemes/LiveApple.xcscheme b/LiveApple.xcodeproj/xcshareddata/xcschemes/LiveApple.xcscheme new file mode 100644 index 0000000..4c05123 --- /dev/null +++ b/LiveApple.xcodeproj/xcshareddata/xcschemes/LiveApple.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LiveApple/Activities.swift b/LiveApple/Activities.swift new file mode 100644 index 0000000..dc59ba2 --- /dev/null +++ b/LiveApple/Activities.swift @@ -0,0 +1,15 @@ +// +// Activities.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import Foundation +import ActivityKit + +struct BadAppleAttributes: ActivityAttributes { + struct ContentState: Codable, Hashable { + let frame: Frame + } +} diff --git a/LiveApple/Assets.xcassets/AccentColor.colorset/Contents.json b/LiveApple/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/LiveApple/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LiveApple/Assets.xcassets/AppIcon.appiconset/Contents.json b/LiveApple/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/LiveApple/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LiveApple/Assets.xcassets/Contents.json b/LiveApple/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LiveApple/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LiveApple/BackgroundManager.swift b/LiveApple/BackgroundManager.swift new file mode 100644 index 0000000..5b737ad --- /dev/null +++ b/LiveApple/BackgroundManager.swift @@ -0,0 +1,55 @@ +// +// BackgroundManager.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import Foundation +import BackgroundTasks +import Combine +import CoreLocation +import MediaPlayer + +@MainActor +class BackgroundManager: NSObject { + private var cancellables = Set() + private var continuation: CheckedContinuation! + private var manager = CLLocationManager() + + init(controller: PlayerController) { + super.init() + + print("running in the background!") + controller.$currentFrame + .sink { [unowned self] newFrame in + Task { + if let newFrame { + await controller.activity?.update(using: BadAppleAttributes.ContentState(frame: newFrame)) +// print("updated!") + } else { + self.continuation.resume() + } + } + } + .store(in: &cancellables) + + // tracking the location lets us stay alive in the background + manager.delegate = self + manager.requestAlwaysAuthorization() + manager.allowsBackgroundLocationUpdates = true + manager.startUpdatingLocation() + } + + func run() async { + await withCheckedContinuation { continuation in + self.continuation = continuation + } + } +} + +extension BackgroundManager: CLLocationManagerDelegate { + func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { + print("location: \(locations.last!)") + } +} diff --git a/LiveApple/ContentView.swift b/LiveApple/ContentView.swift new file mode 100644 index 0000000..ef0f437 --- /dev/null +++ b/LiveApple/ContentView.swift @@ -0,0 +1,79 @@ +// +// ContentView.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import SwiftUI +import AVFoundation +import ActivityKit +import BackgroundTasks +import MediaPlayer + +struct ContentView: View { + @Environment(\.scenePhase) private var scenePhase + let controller: PlayerController? + + var body: some View { + VStack(spacing: 16) { + Spacer() + + if let controller { + ControllerView(controller: controller) + } else { + Text("no controller") + } + + Spacer() + } + .onChange(of: scenePhase) { newValue in + if newValue == .active { + try! AVAudioSession.sharedInstance().setCategory(.playback) + try! AVAudioSession.sharedInstance().setActive(true) + } + } + } +} + +struct ControllerView: View { + @ObservedObject var controller: PlayerController + @State var hasStarted = false + + var body: some View { + PlayerView(player: controller.player) + .onChange(of: controller.currentFrame) { frame in + guard let frame else { + return + } + + guard !hasStarted else { + return + } + hasStarted = true + + let state = BadAppleAttributes.ContentState(frame: frame) + let attributes = BadAppleAttributes() + + let activity = try! Activity.request(attributes: attributes, contentState: state) + controller.activity = activity + print(activity) + + do { + try BGTaskScheduler.shared.submit(BGProcessingTaskRequest(identifier: "task")) + } catch { + fatalError("submitting task: \(error)") + } + // lol + BGTaskScheduler.shared.perform(Selector(("_simulateLaunchForTaskWithIdentifier:")), with: "task") + } + + if let frame = controller.currentFrame { + FrameView(frame: frame) + } else { + Rectangle() + .fill(.black) + .frame(width: 60 / UIScreen.main.scale, height: 45 / UIScreen.main.scale) + } + } +} diff --git a/LiveApple/Frame+CV.swift b/LiveApple/Frame+CV.swift new file mode 100644 index 0000000..72d11a8 --- /dev/null +++ b/LiveApple/Frame+CV.swift @@ -0,0 +1,75 @@ +// +// Frame+CV.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import Foundation +import CoreVideo +import Accelerate + +extension Frame { + init(pixelBuffer buf: CVPixelBuffer) { + let inputHeight = CVPixelBufferGetHeight(buf) + let inputWidth = CVPixelBufferGetWidth(buf) + let width = inputWidth / 8 + let height = inputHeight / 8 + precondition(width <= 64) + + // something is wonky with the format, sourceBuffer comes out green/white instead of white/black + // but whatever, we can work with that + let inputCVImageFormat = vImageCVImageFormat_CreateWithCVPixelBuffer(buf).takeRetainedValue() + vImageCVImageFormat_SetColorSpace(inputCVImageFormat, CGColorSpaceCreateDeviceRGB()) + + var error = kvImageNoError + + var sourceFormat = vImage_CGImageFormat( + bitsPerComponent: 8, + bitsPerPixel: 32, + colorSpace: nil, + bitmapInfo: CGBitmapInfo(rawValue: CGImageAlphaInfo.last.rawValue), + version: 0, + decode: nil, + renderingIntent: .defaultIntent + ) + var sourceBuffer = vImage_Buffer() + error = vImageBuffer_InitWithCVPixelBuffer(&sourceBuffer, &sourceFormat, buf, inputCVImageFormat, nil, vImage_Flags(kvImageNoFlags)) + defer { sourceBuffer.free() } + precondition(error == kvImageNoError) + + var destBuffer = vImage_Buffer() + error = vImageBuffer_Init(&destBuffer, vImagePixelCount(height), vImagePixelCount(width), sourceFormat.bitsPerPixel, vImage_Flags(kvImageNoFlags)) + defer { destBuffer.free() } + precondition(error == kvImageNoError) + + error = vImageScale_ARGB8888(&sourceBuffer, &destBuffer, nil, vImage_Flags(kvImageNoFlags)) + precondition(error == kvImageNoError) + + let cgImage = vImageCreateCGImageFromBuffer(&destBuffer, &sourceFormat, nil, nil, vImage_Flags(kvImageNoFlags), &error).takeRetainedValue() + precondition(error == kvImageNoError) + + let dataRef = cgImage.dataProvider!.data! + let data = dataRef as Data + + var enc = [UInt64](repeating: 0, count: height) + + for row in 0.. 127 { + rowEnc |= (1 << col) + } + } + enc[row] = rowEnc + } + + self.width = width + self.data = enc + } +} + diff --git a/LiveApple/Frame.swift b/LiveApple/Frame.swift new file mode 100644 index 0000000..1b20ced --- /dev/null +++ b/LiveApple/Frame.swift @@ -0,0 +1,32 @@ +// +// Frame.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import Foundation +import CoreGraphics + +// a frame of video, encoded as 1 pit per pixel +struct Frame: Codable, Hashable { + // each UInt64 is a row + let data: [UInt64] + let width: Int + var height: Int { data.count } + + func createImage() -> CGImage { + var data = [UInt32](repeating: 0, count: width * height) + for row in 0..> col) & 1 == 1 { + data[row * width + col] = 0xffffffff + } + } + } + return data.withUnsafeMutableBytes { ptr in + let context = CGContext(data: ptr.baseAddress, width: width, height: height, bitsPerComponent: 8, bytesPerRow: 4 * width, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue)! + return context.makeImage()! + } + } +} diff --git a/LiveApple/FrameView.swift b/LiveApple/FrameView.swift new file mode 100644 index 0000000..b4ae461 --- /dev/null +++ b/LiveApple/FrameView.swift @@ -0,0 +1,28 @@ +// +// FrameView.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import SwiftUI + +struct FrameView: View { + let frame: Frame + @State var image: UIImage? + let scale = UIScreen.main.scale + + var body: some View { + if let image { + Image(uiImage: image) + .onChange(of: frame) { newValue in + self.image = UIImage(cgImage: newValue.createImage(), scale: scale, orientation: .up) + } + } else { + Text("creating image") + .onAppear { + self.image = UIImage(cgImage: frame.createImage(), scale: scale, orientation: .up) + } + } + } +} diff --git a/LiveApple/Info.plist b/LiveApple/Info.plist new file mode 100644 index 0000000..d1d8014 --- /dev/null +++ b/LiveApple/Info.plist @@ -0,0 +1,20 @@ + + + + + BGTaskSchedulerPermittedIdentifiers + + task + + CFBundleDocumentTypes + + NSSupportsLiveActivities + + UIBackgroundModes + + audio + location + processing + + + diff --git a/LiveApple/LiveApple.entitlements b/LiveApple/LiveApple.entitlements new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/LiveApple/LiveApple.entitlements @@ -0,0 +1,5 @@ + + + + + diff --git a/LiveApple/LiveAppleApp.swift b/LiveApple/LiveAppleApp.swift new file mode 100644 index 0000000..51e1ca8 --- /dev/null +++ b/LiveApple/LiveAppleApp.swift @@ -0,0 +1,44 @@ +// +// LiveAppleApp.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import SwiftUI +import BackgroundTasks + +@main +struct LiveAppleApp: App { + @UIApplicationDelegateAdaptor private var delegate: AppDelegate + @State var controller: PlayerController! + + var body: some Scene { + WindowGroup { + ContentView(controller: controller) + .task { + controller = PlayerController() + delegate.controller = controller + await controller.start() + } + } + } +} + +class AppDelegate: NSObject, UIApplicationDelegate { + var controller: PlayerController! + + func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { + // can't update in the background without going through BackgroundTasks + BGTaskScheduler.shared.register(forTaskWithIdentifier: "task", using: .main) { [unowned self] task in + Task { + await BackgroundManager(controller: self.controller).run() + task.setTaskCompleted(success: true) + } + } + +// application.beginReceivingRemoteControlEvents() + + return true + } +} diff --git a/LiveApple/PlayerController.swift b/LiveApple/PlayerController.swift new file mode 100644 index 0000000..68bdc66 --- /dev/null +++ b/LiveApple/PlayerController.swift @@ -0,0 +1,123 @@ +// +// PlayerController.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import Foundation +import AVKit +import ActivityKit +import AudioToolbox +import MediaPlayer + +@MainActor +class PlayerController: ObservableObject { + private let reader: AVAssetReader + private let readQueue = DispatchQueue(label: "PlayerController reading", qos: .userInitiated) + private let asset: AVAsset + let player: AVPlayer + @Published private(set) var frames: [(CMTime, Frame)] = [] + private var lastPlayedFrameIndex = 0 + @Published var currentFrame: Frame? + var activity: Activity? + private var timer: Timer? + var initializedNowPlaying = false + + init() { + let url = Bundle.main.url(forResource: "badapple", withExtension: "mp4")! + asset = AVURLAsset(url: url) + + player = AVPlayer(playerItem: AVPlayerItem(asset: asset)) + reader = try! AVAssetReader(asset: asset) + + player.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 30), queue: .main) { [weak self] time in + self?.emitFrame(for: time) + } + } + + func start() async { + let track = try! await asset.loadTracks(withMediaType: .video).first! + let trackOutput = AVAssetReaderTrackOutput(track: track, outputSettings: [ + kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange), + ]) + reader.add(trackOutput) + + let date = Date() + print("start reading") + let frames = await withCheckedContinuation { continuation in + self.readQueue.async { + guard self.reader.startReading() else { + fatalError() + } + var frames: [(CMTime, Frame)] = [] + while let buffer = trackOutput.copyNextSampleBuffer() { + frames.append((buffer.presentationTimeStamp, Frame(pixelBuffer: buffer.imageBuffer!))) + } + continuation.resume(returning: frames) + } + } + print("done reading after: \(-date.timeIntervalSinceNow)") + self.frames = frames + + // using the AVPlayer gives you sound +// self.player.play() + + // doing it manually lets you update while in the background + let start = Date() + timer = .scheduledTimer(withTimeInterval: 1/30, repeats: true, block: { [unowned self] _ in + let diff = -start.timeIntervalSinceNow + let cmTime = CMTime(value: CMTimeValue(diff * 1000), timescale: 1000) + Task { + await self.emitFrame(for: cmTime) + } + }) + } + + func stop() { + reader.cancelReading() + } + + func emitFrame(for time: CMTime) { + if let index = frames[lastPlayedFrameIndex...].firstIndex(where: { $0.0 >= time }) { + lastPlayedFrameIndex = index + let (time, frame) = frames[index] +// print("playing frame at \(time)") + currentFrame = frame + +// if !initializedNowPlaying { +// initializedNowPlaying = true +// let artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 60, height: 45)) { _ in +// UIImage(cgImage: frame.createImage()) +// } +// let center = MPNowPlayingInfoCenter.default() +// let duration = Double(asset.duration.value) / Double(asset.duration.timescale) +// center.nowPlayingInfo = [ +// MPMediaItemPropertyTitle: "Bad Apple!", +// MPMediaItemPropertyArtist: "ZUN", +// MPMediaItemPropertyAlbumArtist: "ZUN", +// MPMediaItemPropertyAlbumTitle: "asdf", +// MPMediaItemPropertyArtwork: artwork, +// MPMediaItemPropertyPlaybackDuration: duration as NSNumber, +// MPNowPlayingInfoPropertyMediaType: MPMediaType.music.rawValue, +// MPNowPlayingInfoPropertyAssetURL: Bundle.main.url(forResource: "badapple", withExtension: "mp4")!, +// MPNowPlayingInfoPropertyIsLiveStream: false, +// MPNowPlayingInfoPropertyPlaybackRate: 1.0, +// MPNowPlayingInfoPropertyDefaultPlaybackRate: 1.0, +// ] +// } +// +// +// let artwork = MPMediaItemArtwork(boundsSize: CGSize(width: 60, height: 45)) { size in +// UIImage(cgImage: frame.createImage()) +// } +// var info = MPNowPlayingInfoCenter.default().nowPlayingInfo! +// info[MPMediaItemPropertyArtwork] = artwork +// info[MPMediaItemPropertyTitle] = index.description +// MPNowPlayingInfoCenter.default().nowPlayingInfo = info + } else { + print("no frame") + } + } + +} diff --git a/LiveApple/PlayerView.swift b/LiveApple/PlayerView.swift new file mode 100644 index 0000000..6d71456 --- /dev/null +++ b/LiveApple/PlayerView.swift @@ -0,0 +1,57 @@ +// +// PlayerView.swift +// LiveApple +// +// Created by Shadowfacts on 9/24/22. +// + +import SwiftUI +import AVKit + +struct PlayerView: UIViewRepresentable { + @Environment(\.scenePhase) private var scenePhase + let player: AVPlayer + + func makeUIView(context: Context) -> PlayerViewImpl { + PlayerViewImpl(player: player, scenePhase: scenePhase) + } + + func updateUIView(_ uiView: PlayerViewImpl, context: Context) { + uiView.scenePhase = scenePhase + } +} + +class PlayerViewImpl: UIView { + override class var layerClass: AnyClass { + AVPlayerLayer.self + } + + var playerLayer: AVPlayerLayer { + layer as! AVPlayerLayer + } + + let player: AVPlayer + var scenePhase: ScenePhase { + didSet { + if scenePhase == .active { + playerLayer.player = player + } else { + playerLayer.player = nil + } + } + } + + init(player: AVPlayer, scenePhase: ScenePhase) { + self.player = player + self.scenePhase = scenePhase + + super.init(frame: .zero) + + playerLayer.player = player + } + + required init?(coder: NSCoder) { + fatalError() + } + +} diff --git a/LiveApple/Preview Content/Preview Assets.xcassets/Contents.json b/LiveApple/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/LiveApple/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/LiveApple/badapple.mp4 b/LiveApple/badapple.mp4 new file mode 100644 index 0000000..aed5ba9 Binary files /dev/null and b/LiveApple/badapple.mp4 differ