diff --git a/.DS_Store b/.DS_Store index 7b264ca..d0efd2c 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/frontend/.DS_Store b/frontend/.DS_Store new file mode 100644 index 0000000..8c1bdf7 Binary files /dev/null and b/frontend/.DS_Store differ diff --git a/frontend/src-tauri/.DS_Store b/frontend/src-tauri/.DS_Store new file mode 100644 index 0000000..ea85695 Binary files /dev/null and b/frontend/src-tauri/.DS_Store differ diff --git a/frontend/src-tauri/gen/apple/.DS_Store b/frontend/src-tauri/gen/apple/.DS_Store new file mode 100644 index 0000000..512abb9 Binary files /dev/null and b/frontend/src-tauri/gen/apple/.DS_Store differ diff --git a/frontend/src-tauri/gen/apple/Haystack Sharing/.DS_Store b/frontend/src-tauri/gen/apple/Haystack Sharing/.DS_Store new file mode 100644 index 0000000..aa19317 Binary files /dev/null and b/frontend/src-tauri/gen/apple/Haystack Sharing/.DS_Store differ diff --git a/frontend/src-tauri/gen/apple/Haystack.xcodeproj/project.pbxproj b/frontend/src-tauri/gen/apple/Haystack.xcodeproj/project.pbxproj index c9b479f..899eafa 100644 --- a/frontend/src-tauri/gen/apple/Haystack.xcodeproj/project.pbxproj +++ b/frontend/src-tauri/gen/apple/Haystack.xcodeproj/project.pbxproj @@ -8,7 +8,7 @@ /* Begin PBXBuildFile section */ 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 */; }; 6AAF6095EAF01A93F2CE8305 /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0C62A99D37C1C342BB06981B /* libapp.a */; }; 7123EC8A6063C72E5DA3E659 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BE76A4E4971EE0237680C836 /* QuartzCore.framework */; }; @@ -23,12 +23,12 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 283EED8E2DC6170E00943E7E /* PBXContainerItemProxy */ = { + 28AC4E302DCFF4B000A78D36 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 193F5589816ED16BC8109D31 /* Project object */; proxyType = 1; - remoteGlobalIDString = 283EED852DC6170E00943E7E; - remoteInfo = Haystack; + remoteGlobalIDString = 28AC4E272DCFF4B000A78D36; + remoteInfo = Sharing; }; /* End PBXContainerItemProxy section */ @@ -39,7 +39,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( - 283EED902DC6170E00943E7E /* Haystack.appex in Embed Foundation Extensions */, + 28AC4E322DCFF4B000A78D36 /* Sharing.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -53,7 +53,7 @@ 1C223AE96283F8269EFE1D03 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 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; }; - 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 = ""; }; 3ADC946E8026E7A68FA70BFA /* main.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = main.rs; sourceTree = ""; }; 3B744E798409E96A0E89BC52 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; @@ -75,17 +75,17 @@ /* End PBXFileReference section */ /* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 283EED942DC6170E00943E7E /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { + 28AC4E332DCFF4B000A78D36 /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( Info.plist, ); - target = 283EED852DC6170E00943E7E /* Haystack */; + target = 28AC4E272DCFF4B000A78D36 /* Sharing */; }; /* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ /* Begin PBXFileSystemSynchronizedRootGroup section */ - 283EED872DC6170E00943E7E /* Haystack */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (283EED942DC6170E00943E7E /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Haystack; sourceTree = ""; }; + 28AC4E292DCFF4B000A78D36 /* Sharing */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (28AC4E332DCFF4B000A78D36 /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Sharing; sourceTree = ""; }; /* End PBXFileSystemSynchronizedRootGroup section */ /* Begin PBXFrameworksBuildPhase section */ @@ -104,7 +104,7 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 283EED832DC6170E00943E7E /* Frameworks */ = { + 28AC4E252DCFF4B000A78D36 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( @@ -166,7 +166,7 @@ isa = PBXGroup; children = ( D4A71980828D15BC10ECF3D2 /* Haystack.app */, - 283EED862DC6170E00943E7E /* Haystack.appex */, + 28AC4E282DCFF4B000A78D36 /* Sharing.appex */, ); name = Products; sourceTree = ""; @@ -189,7 +189,7 @@ 5D14D0B3A1E4F17999F21EC3 /* Haystack_iOS */, 99B42F02A0EEA086F70E7F36 /* Sources */, 3976EF9B359101EBE231CF77 /* src */, - 283EED872DC6170E00943E7E /* Haystack */, + 28AC4E292DCFF4B000A78D36 /* Sharing */, 5157718C625E46F07FAC4F7C /* Frameworks */, 84D53E3A8587FE554E32F5F0 /* Products */, ); @@ -214,26 +214,26 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ - 283EED852DC6170E00943E7E /* Haystack */ = { + 28AC4E272DCFF4B000A78D36 /* Sharing */ = { isa = PBXNativeTarget; - buildConfigurationList = 283EED952DC6170E00943E7E /* Build configuration list for PBXNativeTarget "Haystack" */; + buildConfigurationList = 28AC4E342DCFF4B000A78D36 /* Build configuration list for PBXNativeTarget "Sharing" */; buildPhases = ( - 283EED822DC6170E00943E7E /* Sources */, - 283EED832DC6170E00943E7E /* Frameworks */, - 283EED842DC6170E00943E7E /* Resources */, + 28AC4E242DCFF4B000A78D36 /* Sources */, + 28AC4E252DCFF4B000A78D36 /* Frameworks */, + 28AC4E262DCFF4B000A78D36 /* Resources */, ); buildRules = ( ); dependencies = ( ); fileSystemSynchronizedGroups = ( - 283EED872DC6170E00943E7E /* Haystack */, + 28AC4E292DCFF4B000A78D36 /* Sharing */, ); - name = Haystack; + name = Sharing; packageProductDependencies = ( ); - productName = Haystack; - productReference = 283EED862DC6170E00943E7E /* Haystack.appex */; + productName = Sharing; + productReference = 28AC4E282DCFF4B000A78D36 /* Sharing.appex */; productType = "com.apple.product-type.app-extension"; }; 28B448F5673D227E72859E56 /* Haystack_iOS */ = { @@ -249,7 +249,7 @@ buildRules = ( ); dependencies = ( - 283EED8F2DC6170E00943E7E /* PBXTargetDependency */, + 28AC4E312DCFF4B000A78D36 /* PBXTargetDependency */, ); name = Haystack_iOS; packageProductDependencies = ( @@ -268,7 +268,7 @@ LastSwiftUpdateCheck = 1630; LastUpgradeCheck = 1430; TargetAttributes = { - 283EED852DC6170E00943E7E = { + 28AC4E272DCFF4B000A78D36 = { CreatedOnToolsVersion = 16.3; }; }; @@ -287,13 +287,13 @@ projectRoot = ""; targets = ( 28B448F5673D227E72859E56 /* Haystack_iOS */, - 283EED852DC6170E00943E7E /* Haystack */, + 28AC4E272DCFF4B000A78D36 /* Sharing */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 283EED842DC6170E00943E7E /* Resources */ = { + 28AC4E262DCFF4B000A78D36 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -337,7 +337,7 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 283EED822DC6170E00943E7E /* Sources */ = { + 28AC4E242DCFF4B000A78D36 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( @@ -355,10 +355,10 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 283EED8F2DC6170E00943E7E /* PBXTargetDependency */ = { + 28AC4E312DCFF4B000A78D36 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 283EED852DC6170E00943E7E /* Haystack */; - targetProxy = 283EED8E2DC6170E00943E7E /* PBXContainerItemProxy */; + target = 28AC4E272DCFF4B000A78D36 /* Sharing */; + targetProxy = 28AC4E302DCFF4B000A78D36 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -366,7 +366,6 @@ 17EFD3F6173E3547D2B12EE3 /* release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements; @@ -407,7 +406,7 @@ }; name = release; }; - 283EED922DC6170E00943E7E /* debug */ = { + 28AC4E352DCFF4B000A78D36 /* debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -440,8 +439,8 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = Haystack/Haystack.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_ENTITLEMENTS = Sharing/Sharingdebug.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; @@ -465,8 +464,8 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = Haystack/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = Haystack; + INFOPLIST_FILE = Sharing/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Sharing; INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 18.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -479,7 +478,7 @@ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Haystack; + PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Sharing; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -491,7 +490,7 @@ }; name = debug; }; - 283EED932DC6170E00943E7E /* release */ = { + 28AC4E362DCFF4B000A78D36 /* release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; @@ -524,8 +523,8 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - CODE_SIGN_ENTITLEMENTS = Haystack/Haystack.entitlements; - CODE_SIGN_IDENTITY = "iPhone Developer"; + CODE_SIGN_ENTITLEMENTS = Sharing/Sharingrelease.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; @@ -543,8 +542,8 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = Haystack/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = Haystack; + INFOPLIST_FILE = Sharing/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Sharing; INFOPLIST_KEY_NSHumanReadableCopyright = ""; IPHONEOS_DEPLOYMENT_TARGET = 18.4; LD_RUNPATH_SEARCH_PATHS = ( @@ -556,7 +555,7 @@ MARKETING_VERSION = 1.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Haystack; + PRODUCT_BUNDLE_IDENTIFIER = com.haystack.app.Sharing; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SKIP_INSTALL = YES; @@ -690,7 +689,6 @@ C03D1D76D6D372BC34FF4DFD /* debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ARCHS = arm64; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = Haystack_iOS/Haystack_iOS.entitlements; @@ -734,11 +732,11 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 283EED952DC6170E00943E7E /* Build configuration list for PBXNativeTarget "Haystack" */ = { + 28AC4E342DCFF4B000A78D36 /* Build configuration list for PBXNativeTarget "Sharing" */ = { isa = XCConfigurationList; buildConfigurations = ( - 283EED922DC6170E00943E7E /* debug */, - 283EED932DC6170E00943E7E /* release */, + 28AC4E352DCFF4B000A78D36 /* debug */, + 28AC4E362DCFF4B000A78D36 /* release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = debug; diff --git a/frontend/src-tauri/gen/apple/Sharing/Base.lproj/MainInterface.storyboard b/frontend/src-tauri/gen/apple/Sharing/Base.lproj/MainInterface.storyboard new file mode 100644 index 0000000..286a508 --- /dev/null +++ b/frontend/src-tauri/gen/apple/Sharing/Base.lproj/MainInterface.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src-tauri/gen/apple/Sharing/Info.plist b/frontend/src-tauri/gen/apple/Sharing/Info.plist new file mode 100644 index 0000000..8420861 --- /dev/null +++ b/frontend/src-tauri/gen/apple/Sharing/Info.plist @@ -0,0 +1,31 @@ + + + + + NSExtension + + NSExtensionAttributes + + NSExtensionActivationRule + + NSExtensionActivationSupportsImageWithMaxCount + 1 + NSExtensionActivationSupportsMovieWithMaxCount + 0 + NSExtensionActivationSupportsFileWithMaxCount + 0 + NSExtensionActivationSupportsText + + NSExtensionActivationSupportsWebURLWithMaxCount + 0 + NSExtensionActivationSupportsWebPageWithMaxCount + 0 + + + NSExtensionMainStoryboard + MainInterface + NSExtensionPointIdentifier + com.apple.share-services + + + diff --git a/frontend/src-tauri/gen/apple/Sharing/ShareViewController.swift b/frontend/src-tauri/gen/apple/Sharing/ShareViewController.swift new file mode 100644 index 0000000..28e93bd --- /dev/null +++ b/frontend/src-tauri/gen/apple/Sharing/ShareViewController.swift @@ -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[.. 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[.. [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 [] + } +} diff --git a/frontend/src-tauri/gen/apple/Sharing/Sharingdebug.entitlements b/frontend/src-tauri/gen/apple/Sharing/Sharingdebug.entitlements new file mode 100644 index 0000000..847b16e --- /dev/null +++ b/frontend/src-tauri/gen/apple/Sharing/Sharingdebug.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.haystack.app + + + diff --git a/frontend/src-tauri/gen/apple/Sharing/Sharingrelease.entitlements b/frontend/src-tauri/gen/apple/Sharing/Sharingrelease.entitlements new file mode 100644 index 0000000..847b16e --- /dev/null +++ b/frontend/src-tauri/gen/apple/Sharing/Sharingrelease.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.application-groups + + group.com.haystack.app + + + diff --git a/frontend/src-tauri/tauri.conf.json b/frontend/src-tauri/tauri.conf.json index 711ee51..7863ea8 100644 --- a/frontend/src-tauri/tauri.conf.json +++ b/frontend/src-tauri/tauri.conf.json @@ -25,6 +25,9 @@ "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico" - ] + ], + "macOS": { + "signingIdentity": "6F3F957C06DE870B9A9F2CA8C2E762C6752AB2CB" + } } }