feat: setting up a different share extension

idk what happened to the old one
This commit is contained in:
Rio Keefe
2025-05-10 22:18:49 +01:00
parent b97eae10a3
commit a9749f062e
12 changed files with 295 additions and 47 deletions

BIN
.DS_Store vendored

Binary file not shown.

BIN
frontend/.DS_Store vendored Normal file

Binary file not shown.

BIN
frontend/src-tauri/.DS_Store vendored Normal file

Binary file not shown.

BIN
frontend/src-tauri/gen/apple/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
16C383BC47682E60119C08CB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21497598D6296AB30C0EBA84 /* UIKit.framework */; }; 16C383BC47682E60119C08CB /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 21497598D6296AB30C0EBA84 /* UIKit.framework */; };
283EED902DC6170E00943E7E /* Haystack.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 283EED862DC6170E00943E7E /* Haystack.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 28AC4E322DCFF4B000A78D36 /* Sharing.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 28AC4E282DCFF4B000A78D36 /* Sharing.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
4CF1B89C17C5E734976BEFBE /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C6D4774DE6800DAE9E77C70 /* Metal.framework */; }; 4CF1B89C17C5E734976BEFBE /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C6D4774DE6800DAE9E77C70 /* Metal.framework */; };
6AAF6095EAF01A93F2CE8305 /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C62A99D37C1C342BB06981B /* libapp.a */; }; 6AAF6095EAF01A93F2CE8305 /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C62A99D37C1C342BB06981B /* libapp.a */; };
7123EC8A6063C72E5DA3E659 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE76A4E4971EE0237680C836 /* QuartzCore.framework */; }; 7123EC8A6063C72E5DA3E659 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE76A4E4971EE0237680C836 /* QuartzCore.framework */; };
@ -23,12 +23,12 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
283EED8E2DC6170E00943E7E /* PBXContainerItemProxy */ = { 28AC4E302DCFF4B000A78D36 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy; isa = PBXContainerItemProxy;
containerPortal = 193F5589816ED16BC8109D31 /* Project object */; containerPortal = 193F5589816ED16BC8109D31 /* Project object */;
proxyType = 1; proxyType = 1;
remoteGlobalIDString = 283EED852DC6170E00943E7E; remoteGlobalIDString = 28AC4E272DCFF4B000A78D36;
remoteInfo = Haystack; remoteInfo = Sharing;
}; };
/* End PBXContainerItemProxy section */ /* End PBXContainerItemProxy section */
@ -39,7 +39,7 @@
dstPath = ""; dstPath = "";
dstSubfolderSpec = 13; dstSubfolderSpec = 13;
files = ( files = (
283EED902DC6170E00943E7E /* Haystack.appex in Embed Foundation Extensions */, 28AC4E322DCFF4B000A78D36 /* Sharing.appex in Embed Foundation Extensions */,
); );
name = "Embed Foundation Extensions"; name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@ -53,7 +53,7 @@
1C223AE96283F8269EFE1D03 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 1C223AE96283F8269EFE1D03 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
1ECBDB6420B28D950ADFD5BD /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 1ECBDB6420B28D950ADFD5BD /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
21497598D6296AB30C0EBA84 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 21497598D6296AB30C0EBA84 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
283EED862DC6170E00943E7E /* Haystack.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Haystack.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 28AC4E282DCFF4B000A78D36 /* Sharing.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = Sharing.appex; sourceTree = BUILT_PRODUCTS_DIR; };
2CE665AA7ABC7563C685FAA6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; }; 2CE665AA7ABC7563C685FAA6 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
3ADC946E8026E7A68FA70BFA /* main.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = main.rs; sourceTree = "<group>"; }; 3ADC946E8026E7A68FA70BFA /* main.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = main.rs; sourceTree = "<group>"; };
3B744E798409E96A0E89BC52 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; }; 3B744E798409E96A0E89BC52 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
@ -75,17 +75,17 @@
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
283EED942DC6170E00943E7E /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { 28AC4E332DCFF4B000A78D36 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet; isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = ( membershipExceptions = (
Info.plist, Info.plist,
); );
target = 283EED852DC6170E00943E7E /* Haystack */; target = 28AC4E272DCFF4B000A78D36 /* Sharing */;
}; };
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFileSystemSynchronizedRootGroup section */
283EED872DC6170E00943E7E /* Haystack */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (283EED942DC6170E00943E7E /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Haystack; sourceTree = "<group>"; }; 28AC4E292DCFF4B000A78D36 /* Sharing */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (28AC4E332DCFF4B000A78D36 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Sharing; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */ /* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -104,7 +104,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
283EED832DC6170E00943E7E /* Frameworks */ = { 28AC4E252DCFF4B000A78D36 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@ -166,7 +166,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D4A71980828D15BC10ECF3D2 /* Haystack.app */, D4A71980828D15BC10ECF3D2 /* Haystack.app */,
283EED862DC6170E00943E7E /* Haystack.appex */, 28AC4E282DCFF4B000A78D36 /* Sharing.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -189,7 +189,7 @@
5D14D0B3A1E4F17999F21EC3 /* Haystack_iOS */, 5D14D0B3A1E4F17999F21EC3 /* Haystack_iOS */,
99B42F02A0EEA086F70E7F36 /* Sources */, 99B42F02A0EEA086F70E7F36 /* Sources */,
3976EF9B359101EBE231CF77 /* src */, 3976EF9B359101EBE231CF77 /* src */,
283EED872DC6170E00943E7E /* Haystack */, 28AC4E292DCFF4B000A78D36 /* Sharing */,
5157718C625E46F07FAC4F7C /* Frameworks */, 5157718C625E46F07FAC4F7C /* Frameworks */,
84D53E3A8587FE554E32F5F0 /* Products */, 84D53E3A8587FE554E32F5F0 /* Products */,
); );
@ -214,26 +214,26 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
283EED852DC6170E00943E7E /* Haystack */ = { 28AC4E272DCFF4B000A78D36 /* Sharing */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 283EED952DC6170E00943E7E /* Build configuration list for PBXNativeTarget "Haystack" */; buildConfigurationList = 28AC4E342DCFF4B000A78D36 /* Build configuration list for PBXNativeTarget "Sharing" */;
buildPhases = ( buildPhases = (
283EED822DC6170E00943E7E /* Sources */, 28AC4E242DCFF4B000A78D36 /* Sources */,
283EED832DC6170E00943E7E /* Frameworks */, 28AC4E252DCFF4B000A78D36 /* Frameworks */,
283EED842DC6170E00943E7E /* Resources */, 28AC4E262DCFF4B000A78D36 /* Resources */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
); );
fileSystemSynchronizedGroups = ( fileSystemSynchronizedGroups = (
283EED872DC6170E00943E7E /* Haystack */, 28AC4E292DCFF4B000A78D36 /* Sharing */,
); );
name = Haystack; name = Sharing;
packageProductDependencies = ( packageProductDependencies = (
); );
productName = Haystack; productName = Sharing;
productReference = 283EED862DC6170E00943E7E /* Haystack.appex */; productReference = 28AC4E282DCFF4B000A78D36 /* Sharing.appex */;
productType = "com.apple.product-type.app-extension"; productType = "com.apple.product-type.app-extension";
}; };
28B448F5673D227E72859E56 /* Haystack_iOS */ = { 28B448F5673D227E72859E56 /* Haystack_iOS */ = {
@ -249,7 +249,7 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
283EED8F2DC6170E00943E7E /* PBXTargetDependency */, 28AC4E312DCFF4B000A78D36 /* PBXTargetDependency */,
); );
name = Haystack_iOS; name = Haystack_iOS;
packageProductDependencies = ( packageProductDependencies = (
@ -268,7 +268,7 @@
LastSwiftUpdateCheck = 1630; LastSwiftUpdateCheck = 1630;
LastUpgradeCheck = 1430; LastUpgradeCheck = 1430;
TargetAttributes = { TargetAttributes = {
283EED852DC6170E00943E7E = { 28AC4E272DCFF4B000A78D36 = {
CreatedOnToolsVersion = 16.3; CreatedOnToolsVersion = 16.3;
}; };
}; };
@ -287,13 +287,13 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
28B448F5673D227E72859E56 /* Haystack_iOS */, 28B448F5673D227E72859E56 /* Haystack_iOS */,
283EED852DC6170E00943E7E /* Haystack */, 28AC4E272DCFF4B000A78D36 /* Sharing */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
283EED842DC6170E00943E7E /* Resources */ = { 28AC4E262DCFF4B000A78D36 /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@ -337,7 +337,7 @@
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
283EED822DC6170E00943E7E /* Sources */ = { 28AC4E242DCFF4B000A78D36 /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@ -355,10 +355,10 @@
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */ /* Begin PBXTargetDependency section */
283EED8F2DC6170E00943E7E /* PBXTargetDependency */ = { 28AC4E312DCFF4B000A78D36 /* PBXTargetDependency */ = {
isa = PBXTargetDependency; isa = PBXTargetDependency;
target = 283EED852DC6170E00943E7E /* Haystack */; target = 28AC4E272DCFF4B000A78D36 /* Sharing */;
targetProxy = 283EED8E2DC6170E00943E7E /* PBXContainerItemProxy */; targetProxy = 28AC4E302DCFF4B000A78D36 /* PBXContainerItemProxy */;
}; };
/* End PBXTargetDependency section */ /* End PBXTargetDependency section */
@ -366,7 +366,6 @@
17EFD3F6173E3547D2B12EE3 /* release */ = { 17EFD3F6173E3547D2B12EE3 /* release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = arm64; ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements; CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements;
@ -407,7 +406,7 @@
}; };
name = release; name = release;
}; };
283EED922DC6170E00943E7E /* debug */ = { 28AC4E352DCFF4B000A78D36 /* debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
@ -440,8 +439,8 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = Haystack/Haystack.entitlements; CODE_SIGN_ENTITLEMENTS = Sharing/Sharingdebug.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@ -465,8 +464,8 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Haystack/Info.plist; INFOPLIST_FILE = Sharing/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Haystack; INFOPLIST_KEY_CFBundleDisplayName = Sharing;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 18.4; IPHONEOS_DEPLOYMENT_TARGET = 18.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@ -479,7 +478,7 @@
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Haystack; PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Sharing;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -491,7 +490,7 @@
}; };
name = debug; name = debug;
}; };
283EED932DC6170E00943E7E /* release */ = { 28AC4E362DCFF4B000A78D36 /* release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO; ALWAYS_SEARCH_USER_PATHS = NO;
@ -524,8 +523,8 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = Haystack/Haystack.entitlements; CODE_SIGN_ENTITLEMENTS = Sharing/Sharingrelease.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
@ -543,8 +542,8 @@
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = Haystack/Info.plist; INFOPLIST_FILE = Sharing/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = Haystack; INFOPLIST_KEY_CFBundleDisplayName = Sharing;
INFOPLIST_KEY_NSHumanReadableCopyright = ""; INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 18.4; IPHONEOS_DEPLOYMENT_TARGET = 18.4;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
@ -556,7 +555,7 @@
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES; MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Haystack; PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Sharing;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SKIP_INSTALL = YES; SKIP_INSTALL = YES;
@ -690,7 +689,6 @@
C03D1D76D6D372BC34FF4DFD /* debug */ = { C03D1D76D6D372BC34FF4DFD /* debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
ARCHS = arm64; ARCHS = arm64;
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements; CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements;
@ -734,11 +732,11 @@
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
283EED952DC6170E00943E7E /* Build configuration list for PBXNativeTarget "Haystack" */ = { 28AC4E342DCFF4B000A78D36 /* Build configuration list for PBXNativeTarget "Sharing" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
283EED922DC6170E00943E7E /* debug */, 28AC4E352DCFF4B000A78D36 /* debug */,
283EED932DC6170E00943E7E /* release */, 28AC4E362DCFF4B000A78D36 /* release */,
); );
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = debug; defaultConfigurationName = debug;

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Share View Controller-->
<scene sceneID="ceB-am-kn3">
<objects>
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>0</integer>
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>0</integer>
<key>NSExtensionActivationSupportsText</key>
<false/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>0</integer>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>0</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,172 @@
//
//
//  ShareViewController.swift
//  Haystack
//
//  Created by Rio Keefe on 03/05/2025.
//
import UIKit
import Social
import MobileCoreServices
class ShareViewController: SLComposeServiceViewController {
let appGroupName = "group.com.haystack.app" // Replace with your actual App Group identifier
let tokenKey = "sharedAuthToken"
let uploadURL = URL(string: "https://haystack.johncosta.tech/image/")!
var bearerToken: String?
// Store the item provider to access it later in didSelectPost
private var imageItemProvider: NSItemProvider?
private var extractedImageName: String = "image" // Default name
override func viewDidLoad() {
super.viewDidLoad()
// Load the bearer token from the App Group in viewDidLoad
// This is okay as reading from UserDefaults is fast
if let sharedDefaults = UserDefaults(suiteName: appGroupName) {
bearerToken = sharedDefaults.string(forKey: tokenKey)
print("Retrieved bearer token: \(bearerToken ?? "nil")")
} else {
print("Error accessing App Group UserDefaults.")
// Optionally inform the user or disable posting if token is crucial
// self.isContentValid() could check if bearerToken is nil
}
// Store the item provider, but don't load the data synchronously yet
if let item = extensionContext?.inputItems.first as? NSExtensionItem,
let provider = item.attachments?.first as? NSItemProvider {
if provider.hasItemConformingToTypeIdentifier(kUTTypeImage as String) {
self.imageItemProvider = provider
// Attempt to get a suggested name early if available
extractedImageName = provider.suggestedName ?? "image"
if let dotRange = extractedImageName.range(of: ".", options: .backwards) {
extractedImageName = String(extractedImageName[..<dotRange.lowerBound])
}
} else {
print("No image found.")
// If no image is found, the content is not valid for this extension
// You might want to adjust isContentValid() based on this
}
}
}
override func isContentValid() -> Bool {
// Content is valid only if we have an item provider for an image AND a bearer token
return imageItemProvider != nil && bearerToken != nil
}
override func didSelectPost() {
// This method is called when the user taps the "Post" button.
// Start the asynchronous operation here.
guard let provider = imageItemProvider else {
print("Error: No image item provider found when posting.")
// Inform the user or log an error
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
return
}
guard let token = bearerToken else {
print("Error: Bearer token is missing when posting.")
// Inform the user or log an error
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
return
}
// Load the image data asynchronously
provider.loadItem(forTypeIdentifier: kUTTypeImage as String, options: nil) { [weak self] (item, error) in
guard let self = self else { return }
if let error = error {
print("Error loading image data for upload: \(error.localizedDescription)")
// Inform the user about the failure
self.extensionContext!.cancelRequest(withError: error)
return
}
var rawImageData: Data?
var finalImageName = self.extractedImageName // Use the name extracted earlier
if let url = item as? URL, let data = try? Data(contentsOf: url) {
rawImageData = data
// Refine the name extraction here if necessary, though doing it in viewDidLoad is also an option
finalImageName = url.lastPathComponent
if let dotRange = finalImageName.range(of: ".", options: .backwards) {
finalImageName = String(finalImageName[..<dotRange.lowerBound])
}
} else if let data = item as? Data {
rawImageData = data
// Use the suggested name if available, fallback to default
finalImageName = provider.suggestedName ?? "image"
} else {
print("Error: Could not get image data in a usable format.")
// Inform the user about the failure
self.extensionContext!.cancelRequest(withError: NSError(domain: "ShareExtension", code: -4, userInfo: [NSLocalizedDescriptionKey: "Could not process image data."]))
return
}
guard let dataToUpload = rawImageData else {
print("Error: No image data to upload.")
// Inform the user about the failure
self.extensionContext!.cancelRequest(withError: NSError(domain: "ShareExtension", code: -5, userInfo: [NSLocalizedDescriptionKey: "Image data is missing."]))
return
}
// Now perform the upload asynchronously
self.uploadRawData(dataToUpload, imageName: finalImageName, bearerToken: token)
}
// Do not complete the request here.
// The request will be completed in the uploadRawData completion handler.
}
func uploadRawData(_ rawData: Data, imageName: String, bearerToken: String) {
// bearerToken is guaranteed to be non-nil here due to the guard in didSelectPost
let uploadURLwithName = uploadURL.appendingPathComponent(imageName)
var request = URLRequest(url: uploadURLwithName)
request.httpMethod = "POST"
request.httpBody = rawData
request.setValue("application/oclet-stream", forHTTPHeaderField: "Content-Type")
request.setValue("Bearer \(bearerToken)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { [weak self] (data, response, error) in
// **IMPORTANT:** Complete the extension request on the main thread
DispatchQueue.main.async {
print("Upload finished. Error: \(error?.localizedDescription ?? "None"), Response: \(response?.description ?? "None")")
if let error = error {
// Handle upload error (e.g., show an alert to the user)
print("Upload failed: \(error.localizedDescription)")
self?.extensionContext!.cancelRequest(withError: error)
} else if let httpResponse = response as? HTTPURLResponse, !(200...299).contains(httpResponse.statusCode) {
// Handle non-success HTTP status codes
let errorDescription = "Server returned status code \(httpResponse.statusCode)"
print(errorDescription)
self?.extensionContext!.cancelRequest(withError: NSError(domain: "ShareExtension", code: httpResponse.statusCode, userInfo: [NSLocalizedDescriptionKey: errorDescription]))
}
else {
// Upload was successful
print("Upload successful")
// Complete the request when the upload is done
self?.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
}
task.resume()
}
override func configurationItems() -> [Any]! {
// You can add items here if you want to allow the user to enter additional info
// e.g., a text field for a caption.
// This example only handles image upload, so no config items are needed.
return []
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.haystack.app</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.haystack.app</string>
</array>
</dict>
</plist>

View File

@ -25,6 +25,9 @@
"icons/128x128@2x.png", "icons/128x128@2x.png",
"icons/icon.icns", "icons/icon.icns",
"icons/icon.ico" "icons/icon.ico"
] ],
"macOS": {
"signingIdentity": "6F3F957C06DE870B9A9F2CA8C2E762C6752AB2CB"
}
} }
} }