feat(mobile): add share sheet functionality

This commit is contained in:
daniel31x13
2025-08-12 10:39:01 -04:00
parent ac8dacd570
commit 89122ccd5c
43 changed files with 1325 additions and 117 deletions

View File

@@ -86,9 +86,9 @@ android {
buildToolsVersion rootProject.ext.buildToolsVersion
compileSdk rootProject.ext.compileSdkVersion
namespace 'com.anonymous.mobileapp'
namespace 'com.anonymous.linkwarden'
defaultConfig {
applicationId 'com.anonymous.mobileapp'
applicationId 'com.anonymous.linkwarden'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1

View File

@@ -24,9 +24,27 @@
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="myapp"/>
<data android:scheme="com.anonymous.mobileapp"/>
<data android:scheme="exp+mobile-app"/>
<data android:scheme="linkwarden"/>
<data android:scheme="com.anonymous.linkwarden"/>
<data android:scheme="exp+linkwarden"/>
<data android:scheme="linkwarden"/>
<data android:scheme="com.anonymous.linkwarden"/>
<data android:scheme="exp+linkwarden"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="text/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="text/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="text/*"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>

View File

@@ -1,4 +1,4 @@
package com.anonymous.mobileapp
package com.anonymous.linkwarden
import expo.modules.splashscreen.SplashScreenManager
import android.os.Build

View File

@@ -1,4 +1,4 @@
package com.anonymous.mobileapp
package com.anonymous.linkwarden
import android.app.Application
import android.content.res.Configuration

View File

@@ -4,4 +4,5 @@
<color name="colorPrimary">#023c69</color>
<color name="colorPrimaryDark">#ffffff</color>
<color name="colorBase">#000000</color>
<color name="navigationBarColor">#ffffff</color>
</resources>

View File

@@ -1,5 +1,5 @@
<resources>
<string name="app_name">mobile-app</string>
<string name="app_name">Linkwarden</string>
<string name="expo_system_ui_user_interface_style" translatable="false">automatic</string>
<string name="expo_splash_screen_resize_mode" translatable="false">contain</string>
<string name="expo_splash_screen_status_bar_translucent" translatable="false">false</string>

View File

@@ -4,8 +4,10 @@
<item name="android:editTextStyle">@style/ResetEditText</item>
<item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
<item name="colorPrimary">@color/colorPrimary</item>
<item name="android:statusBarColor">@android:color/transparent</item>
<item name="android:navigationBarColor">@android:color/transparent</item>
<item name="android:statusBarColor">#ffffff</item>
<item name="android:navigationBarColor">@color/navigationBarColor</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowLightNavigationBar">true</item>
</style>
<style name="ResetEditText" parent="@android:style/Widget.EditText">
<item name="android:padding">0dp</item>

View File

@@ -21,7 +21,7 @@ extensions.configure(com.facebook.react.ReactSettingsExtension) { ex ->
}
}
rootProject.name = 'mobile-app'
rootProject.name = 'Linkwarden'
dependencyResolutionManagement {
versionCatalogs {

View File

@@ -1,23 +1,23 @@
{
"expo": {
"name": "mobile-app",
"slug": "mobile-app",
"name": "Linkwarden",
"slug": "linkwarden",
"version": "1.0.0",
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "myapp",
"scheme": "linkwarden",
"userInterfaceStyle": "automatic",
"newArchEnabled": true,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.anonymous.mobile-app"
"bundleIdentifier": "com.anonymous.linkwarden"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.anonymous.mobileapp"
"package": "com.anonymous.linkwarden"
},
"web": {
"bundler": "metro",
@@ -35,10 +35,20 @@
"backgroundColor": "#ffffff"
}
],
"expo-secure-store"
"expo-secure-store",
"expo-share-intent"
],
"experiments": {
"typedRoutes": true
},
"androidStatusBar": {
"backgroundColor": "#ffffff",
"barStyle": "dark-content",
"translucent": false
},
"androidNavigationBar": {
"backgroundColor": "#ffffff",
"barStyle": "dark-content"
}
}
}

View File

@@ -2,7 +2,7 @@ import { Stack } from "expo-router";
import { QueryClient } from "@tanstack/react-query";
import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client";
import { mmkvPersister } from "@/lib/queryPersister";
import { useState } from "react";
import { useState, useEffect } from "react";
import "../styles/global.css";
import { SheetProvider } from "react-native-actions-sheet";
import "@/components/ActionSheets/Sheets";
@@ -10,6 +10,7 @@ import { useColorScheme } from "nativewind";
import { lightTheme, darkTheme } from "../lib/theme";
import { Platform, View } from "react-native";
import { rawTheme, ThemeName } from "@/lib/colors";
import { useShareIntent } from "expo-share-intent";
const queryClient = new QueryClient({
defaultOptions: {
@@ -25,6 +26,16 @@ const queryClient = new QueryClient({
export default function RootLayout() {
const [isLoading, setIsLoading] = useState(true);
const { colorScheme } = useColorScheme();
const { hasShareIntent, shareIntent, resetShareIntent, error } =
useShareIntent();
useEffect(() => {
if (hasShareIntent) {
// Handle the share intent
console.log("Received share intent:", shareIntent);
resetShareIntent();
}
}, [hasShareIntent, shareIntent, resetShareIntent]);
return (
<PersistQueryClientProvider

View File

@@ -13,7 +13,7 @@ install! 'cocoapods',
prepare_react_native_project!
target 'mobileapp' do
target 'linkwarden' do
use_expo_modules!
if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'

View File

@@ -265,6 +265,8 @@ PODS:
- Yoga
- ExpoSecureStore (14.0.1):
- ExpoModulesCore
- ExpoShareIntentModule (3.2.3):
- ExpoModulesCore
- ExpoSplashScreen (0.29.24):
- ExpoModulesCore
- ExpoSymbols (0.2.2):
@@ -2234,6 +2236,7 @@ DEPENDENCIES:
- ExpoLinking (from `../../../node_modules/expo-linking/ios`)
- ExpoModulesCore (from `../../../node_modules/expo-modules-core`)
- ExpoSecureStore (from `../../../node_modules/expo-secure-store/ios`)
- ExpoShareIntentModule (from `../../../node_modules/expo-share-intent/ios`)
- ExpoSplashScreen (from `../../../node_modules/expo-splash-screen/ios`)
- ExpoSymbols (from `../../../node_modules/expo-symbols/ios`)
- ExpoSystemUI (from `../../../node_modules/expo-system-ui/ios`)
@@ -2367,6 +2370,8 @@ EXTERNAL SOURCES:
:path: "../../../node_modules/expo-modules-core"
ExpoSecureStore:
:path: "../../../node_modules/expo-secure-store/ios"
ExpoShareIntentModule:
:path: "../../../node_modules/expo-share-intent/ios"
ExpoSplashScreen:
:path: "../../../node_modules/expo-splash-screen/ios"
ExpoSymbols:
@@ -2551,6 +2556,7 @@ SPEC CHECKSUMS:
ExpoLinking: 0381341519ca7180a3a057d20edb1cf6a908aaf4
ExpoModulesCore: dd965804a882f1dbb6036fceea4d912461aeaa0d
ExpoSecureStore: d006eea5e316283099d46f80a6b10055b89a6008
ExpoShareIntentModule: 695f93483c08c973d4169bcdc9a9acf9c86cd0e3
ExpoSplashScreen: 0e176e85073dfb9686c100c7f9637975d00608dd
ExpoSymbols: b9f255ce49868d46a73f30e12859efeb8117bcad
ExpoSystemUI: fb8213e39d19e0861320fa69eb60cad7a839c080
@@ -2631,6 +2637,6 @@ SPEC CHECKSUMS:
SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748
Yoga: feb4910aba9742cfedc059e2b2902e22ffe9954a
PODFILE CHECKSUM: b2af7c9ae97589d936103870c67c49d75c98e8fb
PODFILE CHECKSUM: ee7cb5e30637d3bb3ed21d4bcad0cdc3aed49b04
COCOAPODS: 1.16.2

View File

@@ -0,0 +1,25 @@
<?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,21 @@
<?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>NSPrivacyAccessedAPITypes</key>
<array>
<dict>
<key>NSPrivacyAccessedAPIType</key>
<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
<key>NSPrivacyAccessedAPITypeReasons</key>
<array>
<string>CA92.1</string>
</array>
</dict>
</array>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTracking</key>
<false/>
</dict>
</plist>

View File

@@ -0,0 +1,41 @@
<?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>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundleDisplayName</key>
<string>Linkwarden - Share Extension</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
<integer>1</integer>
</dict>
<key>NSExtensionJavaScriptPreprocessingFile</key>
<string>ShareExtensionPreprocessor</string>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
<key>AppGroupIdentifier</key>
<string>group.com.anonymous.linkwarden</string>
</dict>
</plist>

View File

@@ -1,5 +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/>
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.anonymous.linkwarden</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,28 @@
class ShareExtensionPreprocessor {
run({ completionFunction }) {
// Extract meta tags and image sources from the document
const metas = {
title: document.title,
};
// Get all meta elements
const metaElements = document.querySelectorAll("meta");
for (const meta of metaElements) {
const name = meta.getAttribute("name") || meta.getAttribute("property");
const content = meta.getAttribute("content");
if (name && content) {
metas[name] = content;
}
}
// Call the completion function with the extracted data
completionFunction({
baseURI: document.baseURI,
meta: JSON.stringify(metas),
});
}
}
var ExtensionPreprocessingJS = new ShareExtensionPreprocessor();

View File

@@ -0,0 +1,660 @@
/*!
* Native module created for Expo Share Intent (https://github.com/achorein/expo-share-intent)
* author: achorein (https://github.com/achorein)
* inspired by :
* - https://ajith-ab.github.io/react-native-receive-sharing-intent/docs/ios#create-share-extension
*/
import MobileCoreServices
import Photos
import Social
import UIKit
class ShareViewController: UIViewController {
let hostAppGroupIdentifier = "group.com.anonymous.linkwarden"
let shareProtocol = "linkwarden"
let sharedKey = "linkwardenShareKey"
var sharedMedia: [SharedMediaFile] = []
var sharedWebUrl: [WebUrl] = []
var sharedText: [String] = []
let imageContentType: String = UTType.image.identifier
let videoContentType: String = UTType.movie.identifier
let textContentType: String = UTType.text.identifier
let urlContentType: String = UTType.url.identifier
let propertyListType: String = UTType.propertyList.identifier
let fileURLType: String = UTType.fileURL.identifier
let pdfContentType: String = UTType.pdf.identifier
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
Task {
guard let extensionContext = self.extensionContext,
let content = extensionContext.inputItems.first as? NSExtensionItem,
let attachments = content.attachments
else {
dismissWithError(message: "No content found")
return
}
for (index, attachment) in (attachments).enumerated() {
if attachment.hasItemConformingToTypeIdentifier(imageContentType) {
await handleImages(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(videoContentType) {
await handleVideos(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(fileURLType) {
await handleFiles(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(pdfContentType) {
await handlePdf(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(propertyListType) {
await handlePrepocessing(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(urlContentType) {
await handleUrl(content: content, attachment: attachment, index: index)
} else if attachment.hasItemConformingToTypeIdentifier(textContentType) {
await handleText(content: content, attachment: attachment, index: index)
} else {
NSLog("[ERROR] content type not handle !\(String(describing: content))")
dismissWithError(message: "content type not handle \(String(describing: content)))")
}
}
}
}
private func handleText(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async {
Task.detached {
if let item = try! await attachment.loadItem(forTypeIdentifier: self.textContentType)
as? String
{
Task { @MainActor in
self.sharedText.append(item)
// If this is the last item, save sharedText in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.sharedText, forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .text)
}
}
} else {
NSLog("[ERROR] Cannot load text content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load text content \(String(describing: content))")
}
}
}
private func handleUrl(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async {
Task.detached {
if let item = try! await attachment.loadItem(forTypeIdentifier: self.urlContentType) as? URL {
Task { @MainActor in
self.sharedWebUrl.append(WebUrl(url: item.absoluteString, meta: ""))
// If this is the last item, save sharedText in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.toData(data: self.sharedWebUrl), forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .weburl)
}
}
} else {
NSLog("[ERROR] Cannot load url content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load url content \(String(describing: content))")
}
}
}
private func handlePrepocessing(content: NSExtensionItem, attachment: NSItemProvider, index: Int)
async
{
Task.detached {
if let item = try! await attachment.loadItem(
forTypeIdentifier: self.propertyListType, options: nil)
as? NSDictionary
{
Task { @MainActor in
if let results = item[NSExtensionJavaScriptPreprocessingResultsKey]
as? NSDictionary
{
NSLog(
"[DEBUG] NSExtensionJavaScriptPreprocessingResultsKey \(String(describing: results))"
)
self.sharedWebUrl.append(
WebUrl(url: results["baseURI"] as! String, meta: results["meta"] as! String))
// If this is the last item, save sharedText in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.toData(data: self.sharedWebUrl), forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .weburl)
}
} else {
NSLog("[ERROR] Cannot load preprocessing results !\(String(describing: content))")
self.dismissWithError(
message: "Cannot load preprocessing results \(String(describing: content))")
}
}
} else {
NSLog("[ERROR] Cannot load preprocessing content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load preprocessing content \(String(describing: content))")
}
}
}
private func handleImages(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async
{
Task.detached {
if let item = try? await attachment.loadItem(forTypeIdentifier: self.imageContentType) {
Task { @MainActor in
var url: URL? = nil
if let dataURL = item as? URL {
url = dataURL
} else if let imageData = item as? UIImage {
url = self.saveScreenshot(imageData)
}
var pixelWidth: Int? = nil
var pixelHeight: Int? = nil
if let imageSource = CGImageSourceCreateWithURL(url! as CFURL, nil) {
if let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil)
as Dictionary?
{
pixelWidth = imageProperties[kCGImagePropertyPixelWidth] as? Int
pixelHeight = imageProperties[kCGImagePropertyPixelHeight] as? Int
// Check orientation and flip size if required
if let orientationNumber = imageProperties[kCGImagePropertyOrientation] as! CFNumber?
{
var orientation: Int = 0
CFNumberGetValue(orientationNumber, .intType, &orientation)
if orientation > 4 {
let temp: Int? = pixelWidth
pixelWidth = pixelHeight
pixelHeight = temp
}
}
}
}
// Always copy
let fileName = self.getFileName(from: url!, type: .image)
let fileExtension = self.getExtension(from: url!, type: .image)
let fileSize = self.getFileSize(from: url!)
let mimeType = url!.mimeType(ext: fileExtension)
let newName = "\(UUID().uuidString).\(fileExtension)"
let newPath = FileManager.default
.containerURL(
forSecurityApplicationGroupIdentifier: self.hostAppGroupIdentifier)!
.appendingPathComponent(newName)
let copied = self.copyFile(at: url!, to: newPath)
if copied {
self.sharedMedia.append(
SharedMediaFile(
path: newPath.absoluteString, thumbnail: nil, fileName: fileName,
fileSize: fileSize, width: pixelWidth, height: pixelHeight, duration: nil,
mimeType: mimeType, type: .image))
}
// If this is the last item, save imagesData in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.toData(data: self.sharedMedia), forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .media)
}
}
} else {
NSLog("[ERROR] Cannot load image content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load image content \(String(describing: content))")
}
}
}
private func documentDirectoryPath() -> URL? {
let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return path.first
}
private func saveScreenshot(_ image: UIImage) -> URL? {
var screenshotURL: URL? = nil
if let screenshotData = image.pngData(),
let screenshotPath = documentDirectoryPath()?.appendingPathComponent("screenshot.png")
{
try? screenshotData.write(to: screenshotPath)
screenshotURL = screenshotPath
}
return screenshotURL
}
private func handleVideos(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async
{
Task.detached {
if let url = try? await attachment.loadItem(forTypeIdentifier: self.videoContentType) as? URL
{
Task { @MainActor in
// Always copy
let fileName = self.getFileName(from: url, type: .video)
let fileExtension = self.getExtension(from: url, type: .video)
let fileSize = self.getFileSize(from: url)
let mimeType = url.mimeType(ext: fileExtension)
let newName = "\(UUID().uuidString).\(fileExtension)"
let newPath = FileManager.default
.containerURL(
forSecurityApplicationGroupIdentifier: self.hostAppGroupIdentifier)!
.appendingPathComponent(newName)
let copied = self.copyFile(at: url, to: newPath)
if copied {
guard
let sharedFile = self.getSharedMediaFile(
forVideo: newPath, fileName: fileName, fileSize: fileSize, mimeType: mimeType)
else {
return
}
self.sharedMedia.append(sharedFile)
}
// If this is the last item, save imagesData in userDefaults and redirect to host app
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.toData(data: self.sharedMedia), forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .media)
}
}
} else {
NSLog("[ERROR] Cannot load video content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load video content \(String(describing: content))")
}
}
}
private func handlePdf(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async {
Task.detached {
if let url = try? await attachment.loadItem(forTypeIdentifier: self.pdfContentType) as? URL {
Task { @MainActor in
await self.handleFileURL(content: content, url: url, index: index)
}
} else {
NSLog("[ERROR] Cannot load pdf content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load pdf content \(String(describing: content))")
}
}
}
private func handleFiles(content: NSExtensionItem, attachment: NSItemProvider, index: Int) async {
Task.detached {
if let url = try? await attachment.loadItem(forTypeIdentifier: self.fileURLType) as? URL {
Task { @MainActor in
await self.handleFileURL(content: content, url: url, index: index)
}
} else {
NSLog("[ERROR] Cannot load file content !\(String(describing: content))")
await self.dismissWithError(
message: "Cannot load file content \(String(describing: content))")
}
}
}
private func handleFileURL(content: NSExtensionItem, url: URL, index: Int) async {
// Always copy
let fileName = self.getFileName(from: url, type: .file)
let fileExtension = self.getExtension(from: url, type: .file)
let fileSize = self.getFileSize(from: url)
let mimeType = url.mimeType(ext: fileExtension)
let newName = "\(UUID().uuidString).\(fileExtension)"
let newPath = FileManager.default
.containerURL(
forSecurityApplicationGroupIdentifier: self.hostAppGroupIdentifier)!
.appendingPathComponent(newName)
let copied = self.copyFile(at: url, to: newPath)
if copied {
self.sharedMedia.append(
SharedMediaFile(
path: newPath.absoluteString, thumbnail: nil, fileName: fileName,
fileSize: fileSize, width: nil, height: nil, duration: nil, mimeType: mimeType,
type: .file))
}
if index == (content.attachments?.count)! - 1 {
let userDefaults = UserDefaults(suiteName: self.hostAppGroupIdentifier)
userDefaults?.set(self.toData(data: self.sharedMedia), forKey: self.sharedKey)
userDefaults?.synchronize()
self.redirectToHostApp(type: .file)
}
}
private func dismissWithError(message: String? = nil) {
DispatchQueue.main.async {
NSLog("[ERROR] Error loading application ! \(message!)")
let alert = UIAlertController(
title: "Error", message: "Error loading application: \(message!)", preferredStyle: .alert)
let action = UIAlertAction(title: "OK", style: .cancel) { _ in
self.dismiss(animated: true, completion: nil)
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
alert.addAction(action)
self.present(alert, animated: true, completion: nil)
}
}
private func redirectToHostApp(type: RedirectType) {
let url = URL(string: "\(shareProtocol)://dataUrl=\(sharedKey)#\(type)")!
var responder = self as UIResponder?
while responder != nil {
if let application = responder as? UIApplication {
if application.canOpenURL(url) {
application.open(url)
} else {
NSLog("redirectToHostApp canOpenURL KO: \(shareProtocol)")
self.dismissWithError(
message: "Application not found, invalid url scheme \(shareProtocol)")
return
}
}
responder = responder!.next
}
extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
enum RedirectType {
case media
case text
case weburl
case file
}
func getExtension(from url: URL, type: SharedMediaType) -> String {
let parts = url.lastPathComponent.components(separatedBy: ".")
var ex: String? = nil
if parts.count > 1 {
ex = parts.last
}
if ex == nil {
switch type {
case .image:
ex = "PNG"
case .video:
ex = "MP4"
case .file:
ex = "TXT"
}
}
return ex ?? "Unknown"
}
func getFileName(from url: URL, type: SharedMediaType) -> String {
var name = url.lastPathComponent
if name == "" {
name = UUID().uuidString + "." + getExtension(from: url, type: type)
}
return name
}
func getFileSize(from url: URL) -> Int? {
do {
let resources = try url.resourceValues(forKeys: [.fileSizeKey])
return resources.fileSize
} catch {
NSLog("Error: \(error)")
return nil
}
}
func copyFile(at srcURL: URL, to dstURL: URL) -> Bool {
do {
if FileManager.default.fileExists(atPath: dstURL.path) {
try FileManager.default.removeItem(at: dstURL)
}
try FileManager.default.copyItem(at: srcURL, to: dstURL)
} catch (let error) {
NSLog("Cannot copy item at \(srcURL) to \(dstURL): \(error)")
return false
}
return true
}
private func getSharedMediaFile(forVideo: URL, fileName: String, fileSize: Int?, mimeType: String)
-> SharedMediaFile?
{
let asset = AVAsset(url: forVideo)
let thumbnailPath = getThumbnailPath(for: forVideo)
let duration = (CMTimeGetSeconds(asset.duration) * 1000).rounded()
var trackWidth: Int? = nil
var trackHeight: Int? = nil
// get video info
let track = asset.tracks(withMediaType: AVMediaType.video).first ?? nil
if track != nil {
let size = track!.naturalSize.applying(track!.preferredTransform)
trackWidth = abs(Int(size.width))
trackHeight = abs(Int(size.height))
}
if FileManager.default.fileExists(atPath: thumbnailPath.path) {
return SharedMediaFile(
path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, fileName: fileName,
fileSize: fileSize, width: trackWidth, height: trackHeight, duration: duration,
mimeType: mimeType, type: .video)
}
var saved = false
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
assetImgGenerate.maximumSize = CGSize(width: 360, height: 360)
do {
let img = try assetImgGenerate.copyCGImage(
at: CMTimeMakeWithSeconds(600, preferredTimescale: Int32(1.0)), actualTime: nil)
try UIImage.pngData(UIImage(cgImage: img))()?.write(to: thumbnailPath)
saved = true
} catch {
saved = false
}
return saved
? SharedMediaFile(
path: forVideo.absoluteString, thumbnail: thumbnailPath.absoluteString, fileName: fileName,
fileSize: fileSize, width: trackWidth, height: trackHeight, duration: duration,
mimeType: mimeType, type: .video) : nil
}
private func getThumbnailPath(for url: URL) -> URL {
let fileName = Data(url.lastPathComponent.utf8).base64EncodedString().replacingOccurrences(
of: "==", with: "")
let path = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: self.hostAppGroupIdentifier)!
.appendingPathComponent("\(fileName).jpg")
return path
}
class WebUrl: Codable {
var url: String
var meta: String
init(url: String, meta: String) {
self.url = url
self.meta = meta
}
}
class SharedMediaFile: Codable {
var path: String // can be image, video or url path
var thumbnail: String? // video thumbnail
var fileName: String // uuid + extension
var fileSize: Int?
var width: Int? // for image
var height: Int? // for image
var duration: Double? // video duration in milliseconds
var mimeType: String
var type: SharedMediaType
init(
path: String, thumbnail: String?, fileName: String, fileSize: Int?, width: Int?, height: Int?,
duration: Double?, mimeType: String, type: SharedMediaType
) {
self.path = path
self.thumbnail = thumbnail
self.fileName = fileName
self.fileSize = fileSize
self.width = width
self.height = height
self.duration = duration
self.mimeType = mimeType
self.type = type
}
}
enum SharedMediaType: Int, Codable {
case image
case video
case file
}
func toData(data: [WebUrl]) -> Data? {
let encodedData = try? JSONEncoder().encode(data)
return encodedData
}
func toData(data: [SharedMediaFile]) -> Data? {
let encodedData = try? JSONEncoder().encode(data)
return encodedData
}
}
internal let mimeTypes = [
"html": "text/html",
"htm": "text/html",
"shtml": "text/html",
"css": "text/css",
"xml": "text/xml",
"gif": "image/gif",
"jpeg": "image/jpeg",
"jpg": "image/jpeg",
"js": "application/javascript",
"atom": "application/atom+xml",
"rss": "application/rss+xml",
"mml": "text/mathml",
"txt": "text/plain",
"jad": "text/vnd.sun.j2me.app-descriptor",
"wml": "text/vnd.wap.wml",
"htc": "text/x-component",
"png": "image/png",
"tif": "image/tiff",
"tiff": "image/tiff",
"wbmp": "image/vnd.wap.wbmp",
"ico": "image/x-icon",
"jng": "image/x-jng",
"bmp": "image/x-ms-bmp",
"svg": "image/svg+xml",
"svgz": "image/svg+xml",
"webp": "image/webp",
"woff": "application/font-woff",
"jar": "application/java-archive",
"war": "application/java-archive",
"ear": "application/java-archive",
"json": "application/json",
"hqx": "application/mac-binhex40",
"doc": "application/msword",
"pdf": "application/pdf",
"ps": "application/postscript",
"eps": "application/postscript",
"ai": "application/postscript",
"rtf": "application/rtf",
"m3u8": "application/vnd.apple.mpegurl",
"xls": "application/vnd.ms-excel",
"eot": "application/vnd.ms-fontobject",
"ppt": "application/vnd.ms-powerpoint",
"wmlc": "application/vnd.wap.wmlc",
"kml": "application/vnd.google-earth.kml+xml",
"kmz": "application/vnd.google-earth.kmz",
"7z": "application/x-7z-compressed",
"cco": "application/x-cocoa",
"jardiff": "application/x-java-archive-diff",
"jnlp": "application/x-java-jnlp-file",
"run": "application/x-makeself",
"pl": "application/x-perl",
"pm": "application/x-perl",
"prc": "application/x-pilot",
"pdb": "application/x-pilot",
"rar": "application/x-rar-compressed",
"rpm": "application/x-redhat-package-manager",
"sea": "application/x-sea",
"swf": "application/x-shockwave-flash",
"sit": "application/x-stuffit",
"tcl": "application/x-tcl",
"tk": "application/x-tcl",
"der": "application/x-x509-ca-cert",
"pem": "application/x-x509-ca-cert",
"crt": "application/x-x509-ca-cert",
"xpi": "application/x-xpinstall",
"xhtml": "application/xhtml+xml",
"xspf": "application/xspf+xml",
"zip": "application/zip",
"epub": "application/epub+zip",
"docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
"mid": "audio/midi",
"midi": "audio/midi",
"kar": "audio/midi",
"mp3": "audio/mpeg",
"ogg": "audio/ogg",
"m4a": "audio/x-m4a",
"ra": "audio/x-realaudio",
"3gpp": "video/3gpp",
"3gp": "video/3gpp",
"ts": "video/mp2t",
"mp4": "video/mp4",
"mpeg": "video/mpeg",
"mpg": "video/mpeg",
"mov": "video/quicktime",
"webm": "video/webm",
"flv": "video/x-flv",
"m4v": "video/x-m4v",
"mng": "video/x-mng",
"asx": "video/x-ms-asf",
"asf": "video/x-ms-asf",
"wmv": "video/x-ms-wmv",
"avi": "video/x-msvideo",
]
extension URL {
func mimeType(ext: String?) -> String {
if #available(iOSApplicationExtension 14.0, *) {
if let pathExt = ext,
let mimeType = UTType(filenameExtension: pathExt)?.preferredMIMEType
{
return mimeType
} else {
return "application/octet-stream"
}
} else {
return mimeTypes[ext?.lowercased() ?? ""] ?? "application/octet-stream"
}
}
}
extension Array {
subscript(safe index: UInt) -> Element? {
return Int(index) < count ? self[Int(index)] : nil
}
}

View File

@@ -10,31 +10,55 @@
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
1EBB68D99EFB4C9A9A990217 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 16DC18B379A6440DA1B05B71 /* MainInterface.storyboard */; };
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
96905EF65AED1B983A6B3ABC /* libPods-mobileapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */; };
5F800AE34BDA4468880DE34C /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E80BF0A4BCA54DBEBD50EA6D /* ShareViewController.swift */; };
820CD026BC2243C5A0D52737 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 6B8F068B4AC94992A6740042 /* PrivacyInfo.xcprivacy */; };
96905EF65AED1B983A6B3ABC /* libPods-linkwarden.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-linkwarden.a */; };
98F5742C729033F29C656840 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */; };
A0D138DDD2D74B9CBA392BD5 /* ShareExtensionPreprocessor.js in Resources */ = {isa = PBXBuildFile; fileRef = 953361A5515E4E70A3EA316D /* ShareExtensionPreprocessor.js */; };
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
D60820CC0DAA4A50A310602F /* ShareExtension.appex in Copy Files */ = {isa = PBXBuildFile; fileRef = 4C20BFFA16E14565933A147B /* ShareExtension.appex */; };
DD111B9AA6FE4075B8E1E6D2 /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = 588141A975DE4C1BBF1048E5 /* noop-file.swift */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
F85132B1A62D418BB04E3B41 /* Copy Files */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
D60820CC0DAA4A50A310602F /* ShareExtension.appex in Copy Files */,
);
name = "Copy Files";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
13B07F961A680F5B00A75B9A /* mobileapp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = mobileapp.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = mobileapp/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = mobileapp/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = mobileapp/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mobileapp/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = mobileapp/main.m; sourceTree = "<group>"; };
51E9021565CB454F93B79E34 /* mobileapp-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "mobileapp-Bridging-Header.h"; path = "mobileapp/mobileapp-Bridging-Header.h"; sourceTree = "<group>"; };
588141A975DE4C1BBF1048E5 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "mobileapp/noop-file.swift"; sourceTree = "<group>"; };
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-mobileapp.a"; sourceTree = BUILT_PRODUCTS_DIR; };
6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobileapp.debug.xcconfig"; path = "Target Support Files/Pods-mobileapp/Pods-mobileapp.debug.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-mobileapp.release.xcconfig"; path = "Target Support Files/Pods-mobileapp/Pods-mobileapp.release.xcconfig"; sourceTree = "<group>"; };
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = mobileapp/SplashScreen.storyboard; sourceTree = "<group>"; };
13B07F961A680F5B00A75B9A /* linkwarden.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = linkwarden.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = linkwarden/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = linkwarden/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = linkwarden/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = linkwarden/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = linkwarden/main.m; sourceTree = "<group>"; };
16DC18B379A6440DA1B05B71 /* MainInterface.storyboard */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = MainInterface.storyboard; path = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/MainInterface.storyboard; sourceTree = "<group>"; };
4C20BFFA16E14565933A147B /* ShareExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = undefined; name = ShareExtension.appex; path = ShareExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
51E9021565CB454F93B79E34 /* linkwarden-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "linkwarden-Bridging-Header.h"; path = "linkwarden/linkwarden-Bridging-Header.h"; sourceTree = "<group>"; };
588141A975DE4C1BBF1048E5 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "linkwarden/noop-file.swift"; sourceTree = "<group>"; };
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-linkwarden.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-linkwarden.a"; sourceTree = BUILT_PRODUCTS_DIR; };
6B8F068B4AC94992A6740042 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = PrivacyInfo.xcprivacy; path = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
6C2E3173556A471DD304B334 /* Pods-linkwarden.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linkwarden.debug.xcconfig"; path = "Target Support Files/Pods-linkwarden/Pods-linkwarden.debug.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-linkwarden.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-linkwarden.release.xcconfig"; path = "Target Support Files/Pods-linkwarden/Pods-linkwarden.release.xcconfig"; sourceTree = "<group>"; };
953361A5515E4E70A3EA316D /* ShareExtensionPreprocessor.js */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = ShareExtensionPreprocessor.js; path = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareExtensionPreprocessor.js; sourceTree = "<group>"; };
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = linkwarden/SplashScreen.storyboard; sourceTree = "<group>"; };
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = mobileapp/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = linkwarden/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
E80BF0A4BCA54DBEBD50EA6D /* ShareViewController.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = ShareViewController.swift; path = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareViewController.swift; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-mobileapp/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-linkwarden/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -42,14 +66,14 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
96905EF65AED1B983A6B3ABC /* libPods-mobileapp.a in Frameworks */,
96905EF65AED1B983A6B3ABC /* libPods-linkwarden.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
13B07FAE1A68108700A75B9A /* mobileapp */ = {
13B07FAE1A68108700A75B9A /* linkwarden */ = {
isa = PBXGroup;
children = (
BB2F792B24A3F905000567C9 /* Supporting */,
@@ -60,17 +84,17 @@
13B07FB71A68108700A75B9A /* main.m */,
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */,
588141A975DE4C1BBF1048E5 /* noop-file.swift */,
51E9021565CB454F93B79E34 /* mobileapp-Bridging-Header.h */,
51E9021565CB454F93B79E34 /* linkwarden-Bridging-Header.h */,
E49C0DC702346D367B33AAEF /* PrivacyInfo.xcprivacy */,
);
name = mobileapp;
name = linkwarden;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-mobileapp.a */,
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-linkwarden.a */,
);
name = Frameworks;
sourceTree = "<group>";
@@ -85,7 +109,7 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* mobileapp */,
13B07FAE1A68108700A75B9A /* linkwarden */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
@@ -100,17 +124,18 @@
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* mobileapp.app */,
13B07F961A680F5B00A75B9A /* linkwarden.app */,
4C20BFFA16E14565933A147B /* ShareExtension.appex */,
);
name = Products;
sourceTree = "<group>";
};
92DBD88DE9BF7D494EA9DA96 /* mobileapp */ = {
92DBD88DE9BF7D494EA9DA96 /* linkwarden */ = {
isa = PBXGroup;
children = (
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */,
);
name = mobileapp;
name = linkwarden;
sourceTree = "<group>";
};
BB2F792B24A3F905000567C9 /* Supporting */ = {
@@ -119,14 +144,14 @@
BB2F792C24A3F905000567C9 /* Expo.plist */,
);
name = Supporting;
path = mobileapp/Supporting;
path = linkwarden/Supporting;
sourceTree = "<group>";
};
D65327D7A22EEC0BE12398D9 /* Pods */ = {
isa = PBXGroup;
children = (
6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */,
7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */,
6C2E3173556A471DD304B334 /* Pods-linkwarden.debug.xcconfig */,
7A4D352CD337FB3A3BF06240 /* Pods-linkwarden.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@@ -134,7 +159,7 @@
D7E4C46ADA2E9064B798F356 /* ExpoModulesProviders */ = {
isa = PBXGroup;
children = (
92DBD88DE9BF7D494EA9DA96 /* mobileapp */,
92DBD88DE9BF7D494EA9DA96 /* linkwarden */,
);
name = ExpoModulesProviders;
sourceTree = "<group>";
@@ -142,9 +167,9 @@
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
13B07F861A680F5B00A75B9A /* mobileapp */ = {
13B07F861A680F5B00A75B9A /* linkwarden */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "mobileapp" */;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "linkwarden" */;
buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */,
33C9CB6682BF7BB3053F48FC /* [Expo] Configure project */,
@@ -154,16 +179,33 @@
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */,
3C1F4EFB27CCA985BA2789D2 /* [CP] Embed Pods Frameworks */,
F85132B1A62D418BB04E3B41 /* Copy Files */,
);
buildRules = (
);
dependencies = (
);
name = mobileapp;
productName = mobileapp;
productReference = 13B07F961A680F5B00A75B9A /* mobileapp.app */;
name = linkwarden;
productName = linkwarden;
productReference = 13B07F961A680F5B00A75B9A /* linkwarden.app */;
productType = "com.apple.product-type.application";
};
61EEC37279BF459FB28735D0 /* ShareExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = A7B886607B3E4CDC87E6AE43 /* Build configuration list for PBXNativeTarget "ShareExtension" */;
buildPhases = (
CA9D67C3EAC2497E839A301F /* Sources */,
5E52F6AB359149EE9F91B71E /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = ShareExtension;
productName = ShareExtension;
productReference = 4C20BFFA16E14565933A147B /* ShareExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
@@ -177,7 +219,7 @@
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "mobileapp" */;
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "linkwarden" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = en;
hasScannedForEncodings = 0;
@@ -190,7 +232,8 @@
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* mobileapp */,
13B07F861A680F5B00A75B9A /* linkwarden */,
61EEC37279BF459FB28735D0 /* ShareExtension */,
);
};
/* End PBXProject section */
@@ -207,6 +250,16 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
5E52F6AB359149EE9F91B71E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A0D138DDD2D74B9CBA392BD5 /* ShareExtensionPreprocessor.js in Resources */,
1EBB68D99EFB4C9A9A990217 /* MainInterface.storyboard in Resources */,
820CD026BC2243C5A0D52737 /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
@@ -240,7 +293,7 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-mobileapp-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-linkwarden-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@@ -264,7 +317,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-mobileapp/expo-configure-project.sh\"\n";
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-linkwarden/expo-configure-project.sh\"\n";
};
3C1F4EFB27CCA985BA2789D2 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
@@ -272,7 +325,7 @@
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-frameworks.sh",
"${PODS_ROOT}/Target Support Files/Pods-linkwarden/Pods-linkwarden-frameworks.sh",
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
);
name = "[CP] Embed Pods Frameworks";
@@ -281,7 +334,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-frameworks.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-linkwarden/Pods-linkwarden-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = {
@@ -290,7 +343,7 @@
files = (
);
inputPaths = (
"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-resources.sh",
"${PODS_ROOT}/Target Support Files/Pods-linkwarden/Pods-linkwarden-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/EXApplication/ExpoApplication_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
@@ -323,7 +376,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-mobileapp/Pods-mobileapp-resources.sh\"\n";
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-linkwarden/Pods-linkwarden-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
@@ -340,23 +393,31 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
CA9D67C3EAC2497E839A301F /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5F800AE34BDA4468880DE34C /* ShareViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-mobileapp.debug.xcconfig */;
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-linkwarden.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = mobileapp/mobileapp.entitlements;
CODE_SIGN_ENTITLEMENTS = linkwarden/linkwarden.entitlements;
CURRENT_PROJECT_VERSION = 1;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = (
"$(inherited)",
"FB_SONARKIT_ENABLED=1",
);
INFOPLIST_FILE = mobileapp/Info.plist;
INFOPLIST_FILE = linkwarden/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
@@ -366,9 +427,9 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.mobile-app";
PRODUCT_NAME = mobileapp;
SWIFT_OBJC_BRIDGING_HEADER = "mobileapp/mobileapp-Bridging-Header.h";
PRODUCT_BUNDLE_IDENTIFIER = com.anonymous.linkwarden;
PRODUCT_NAME = "Linkwarden";
SWIFT_OBJC_BRIDGING_HEADER = "linkwarden/linkwarden-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -378,13 +439,13 @@
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-mobileapp.release.xcconfig */;
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-linkwarden.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = mobileapp/mobileapp.entitlements;
CODE_SIGN_ENTITLEMENTS = linkwarden/linkwarden.entitlements;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = mobileapp/Info.plist;
INFOPLIST_FILE = linkwarden/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0;
@@ -394,9 +455,9 @@
"-lc++",
);
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.mobile-app";
PRODUCT_NAME = mobileapp;
SWIFT_OBJC_BRIDGING_HEADER = "mobileapp/mobileapp-Bridging-Header.h";
PRODUCT_BUNDLE_IDENTIFIER = com.anonymous.linkwarden;
PRODUCT_NAME = "Linkwarden";
SWIFT_OBJC_BRIDGING_HEADER = "linkwarden/linkwarden-Bridging-Header.h";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VERSIONING_SYSTEM = "apple-generic";
@@ -521,10 +582,56 @@
};
name = Release;
};
EA3FC9AE3AB34AE59B5A87C2 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "/Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareExtension-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 1.0.0;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_RELEASE";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.linkwarden.share-extension";
PRODUCT_NAME = ShareExtension;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
F2168D2A3266407BAC3051A2 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = /Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = "/Users/daniel/Desktop/Projects/Linkwarden/workspaces/main/linkwarden/apps/mobile/ios/ShareExtension/ShareExtension-Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 1.0.0;
OTHER_SWIFT_FLAGS = "$(inherited) -D EXPO_CONFIGURATION_DEBUG";
PRODUCT_BUNDLE_IDENTIFIER = "com.anonymous.linkwarden.share-extension";
PRODUCT_NAME = ShareExtension;
SKIP_INSTALL = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "mobileapp" */ = {
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "linkwarden" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
@@ -533,7 +640,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "mobileapp" */ = {
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "linkwarden" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
@@ -542,6 +649,15 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
A7B886607B3E4CDC87E6AE43 /* Build configuration list for PBXNativeTarget "ShareExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
F2168D2A3266407BAC3051A2 /* Debug */,
EA3FC9AE3AB34AE59B5A87C2 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;

View File

@@ -15,9 +15,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "mobileapp.app"
BlueprintName = "mobileapp"
ReferencedContainer = "container:mobileapp.xcodeproj">
BuildableName = "linkwarden.app"
BlueprintName = "linkwarden"
ReferencedContainer = "container:linkwarden.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
@@ -33,9 +33,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "mobileappTests.xctest"
BlueprintName = "mobileappTests"
ReferencedContainer = "container:mobileapp.xcodeproj">
BuildableName = "linkwardenTests.xctest"
BlueprintName = "linkwardenTests"
ReferencedContainer = "container:linkwarden.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
@@ -55,9 +55,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "mobileapp.app"
BlueprintName = "mobileapp"
ReferencedContainer = "container:mobileapp.xcodeproj">
BuildableName = "linkwarden.app"
BlueprintName = "linkwarden"
ReferencedContainer = "container:linkwarden.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
@@ -72,9 +72,9 @@
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "mobileapp.app"
BlueprintName = "mobileapp"
ReferencedContainer = "container:mobileapp.xcodeproj">
BuildableName = "linkwarden.app"
BlueprintName = "linkwarden"
ReferencedContainer = "container:linkwarden.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>

View File

@@ -2,7 +2,7 @@
<Workspace
version = "1.0">
<FileRef
location = "group:mobileapp.xcodeproj">
location = "group:linkwarden.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">

View File

@@ -2,12 +2,14 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppGroupIdentifier</key>
<string>group.com.anonymous.linkwarden</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>mobile-app</string>
<string>Linkwarden</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
@@ -27,14 +29,14 @@
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
<string>com.anonymous.mobile-app</string>
<string>linkwarden</string>
<string>com.anonymous.linkwarden</string>
</array>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>exp+mobile-app</string>
<string>exp+linkwarden</string>
</array>
</dict>
</array>
@@ -44,6 +46,8 @@
<string>12.0</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
@@ -57,6 +61,8 @@
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>SplashScreen</string>
<key>UIRequiredDeviceCapabilities</key>
@@ -83,9 +89,5 @@
<string>Automatic</string>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIFileSharingEnabled</key>
<true/>
<key>LSSupportsOpeningDocumentsInPlace</key>
<true/>
</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.anonymous.linkwarden</string>
</array>
</dict>
</plist>

View File

@@ -1,10 +1,9 @@
{
"name": "mobile-app",
"name": "@linkwarden/mobile",
"main": "expo-router/entry",
"version": "1.0.0",
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
@@ -36,9 +35,10 @@
"expo-file-system": "~18.0.12",
"expo-font": "~13.0.1",
"expo-haptics": "~14.0.0",
"expo-linking": "~7.0.3",
"expo-linking": "~7.0.5",
"expo-router": "4.0.20",
"expo-secure-store": "~14.0.0",
"expo-share-intent": "^3.2.3",
"expo-splash-screen": "~0.29.18",
"expo-status-bar": "~2.0.0",
"expo-symbols": "~0.2.0",

View File

@@ -20,7 +20,7 @@
"prisma:generate": "yarn workspace @linkwarden/prisma generate",
"prisma:studio": "yarn workspace @linkwarden/prisma studio",
"format": "yarn workspaces run format",
"postinstall": "yarn workspace @linkwarden/web run postinstall"
"postinstall": "yarn workspace @linkwarden/web run postinstall && patch-package"
},
"resolutions": {
"@types/react": "18.3.20",
@@ -30,6 +30,7 @@
"dotenv-cli": "^8.0.0"
},
"dependencies": {
"concurrently": "^9.1.2"
"concurrently": "^9.1.2",
"patch-package": "^8.0.0"
}
}

14
patches/xcode+3.0.1.patch Normal file
View File

@@ -0,0 +1,14 @@
diff --git a/node_modules/xcode/lib/pbxProject.js b/node_modules/xcode/lib/pbxProject.js
index 068548a..b478056 100644
--- a/node_modules/xcode/lib/pbxProject.js
+++ b/node_modules/xcode/lib/pbxProject.js
@@ -1678,8 +1678,7 @@ function correctForFrameworksPath(file, project) {
function correctForPath(file, project, group) {
var r_group_dir = new RegExp('^' + group + '[\\\\/]');
-
- if (project.pbxGroupByName(group).path)
+ if (project.pbxGroupByName(group)&&project.pbxGroupByName(group).path)
file.path = file.path.replace(r_group_dir, '');
return file;

267
yarn.lock
View File

@@ -2055,6 +2055,46 @@
node-forge "^1.2.1"
nullthrows "^1.1.1"
"@expo/config-plugins@^9.0.9":
version "9.1.7"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-9.1.7.tgz#cbaaf883c57cd236f157f26c03784adbe6ebf9ac"
integrity sha512-8dJzOesaQS+8XuT49pdSHej1z6XG3x2fqN2O3v807ri8uhxm2N9P6+iZBn19xv9+7OxraOc2tH3nEIWE19Za0w==
dependencies:
"@expo/config-types" "^53.0.0"
"@expo/json-file" "~9.1.3"
"@expo/plist" "^0.3.3"
"@expo/sdk-runtime-versions" "^1.0.0"
chalk "^4.1.2"
debug "^4.3.5"
getenv "^1.0.0"
glob "^10.4.2"
resolve-from "^5.0.0"
semver "^7.5.4"
slash "^3.0.0"
slugify "^1.6.6"
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/config-plugins@~10.1.2":
version "10.1.2"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-10.1.2.tgz#6efa256a3fa2fca116eeb5bef8b22b089e287282"
integrity sha512-IMYCxBOcnuFStuK0Ay+FzEIBKrwW8OVUMc65+v0+i7YFIIe8aL342l7T4F8lR4oCfhXn7d6M5QPgXvjtc/gAcw==
dependencies:
"@expo/config-types" "^53.0.5"
"@expo/json-file" "~9.1.5"
"@expo/plist" "^0.3.5"
"@expo/sdk-runtime-versions" "^1.0.0"
chalk "^4.1.2"
debug "^4.3.5"
getenv "^2.0.0"
glob "^10.4.2"
resolve-from "^5.0.0"
semver "^7.5.4"
slash "^3.0.0"
slugify "^1.6.6"
xcode "^3.0.1"
xml2js "0.6.0"
"@expo/config-plugins@~9.0.17":
version "9.0.17"
resolved "https://registry.yarnpkg.com/@expo/config-plugins/-/config-plugins-9.0.17.tgz#c997072209129b9f9616efa3533314b889cfd788"
@@ -2080,6 +2120,11 @@
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-52.0.5.tgz#e10a226990dd903a4e3db5992ffb3015adf13f38"
integrity sha512-AMDeuDLHXXqd8W+0zSjIt7f37vUd/BP8p43k68NHpyAvQO+z8mbQZm3cNQVAMySeayK2XoPigAFB1JF2NFajaA==
"@expo/config-types@^53.0.0", "@expo/config-types@^53.0.5":
version "53.0.5"
resolved "https://registry.yarnpkg.com/@expo/config-types/-/config-types-53.0.5.tgz#bba7e0712c2c5b1d8963348d68ea96339f858db4"
integrity sha512-kqZ0w44E+HEGBjy+Lpyn0BVL5UANg/tmNixxaRMLS6nf37YsDrLk2VMAmeKMMk5CKG0NmOdVv3ngeUjRQMsy9g==
"@expo/config@~10.0.11":
version "10.0.11"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-10.0.11.tgz#5371ccb3b08ece4c174d5d7009d61e928e6925b0"
@@ -2099,6 +2144,25 @@
slugify "^1.3.4"
sucrase "3.35.0"
"@expo/config@~11.0.12":
version "11.0.13"
resolved "https://registry.yarnpkg.com/@expo/config/-/config-11.0.13.tgz#1cc490a5f667e0129db5f98755f6bc4d8921edb2"
integrity sha512-TnGb4u/zUZetpav9sx/3fWK71oCPaOjZHoVED9NaEncktAd0Eonhq5NUghiJmkUGt3gGSjRAEBXiBbbY9/B1LA==
dependencies:
"@babel/code-frame" "~7.10.4"
"@expo/config-plugins" "~10.1.2"
"@expo/config-types" "^53.0.5"
"@expo/json-file" "^9.1.5"
deepmerge "^4.3.1"
getenv "^2.0.0"
glob "^10.4.2"
require-from-string "^2.0.2"
resolve-from "^5.0.0"
resolve-workspace-root "^2.0.0"
semver "^7.6.0"
slugify "^1.3.4"
sucrase "3.35.0"
"@expo/devcert@^1.1.2":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@expo/devcert/-/devcert-1.2.0.tgz#7b32c2d959e36baaa0649433395e5170c808b44f"
@@ -2119,6 +2183,17 @@
dotenv-expand "~11.0.6"
getenv "^1.0.0"
"@expo/env@~1.0.7":
version "1.0.7"
resolved "https://registry.yarnpkg.com/@expo/env/-/env-1.0.7.tgz#6ee604e158d0f140fc2be711b9a7cb3adc341889"
integrity sha512-qSTEnwvuYJ3umapO9XJtrb1fAqiPlmUUg78N0IZXXGwQRt+bkp0OBls+Y5Mxw/Owj8waAM0Z3huKKskRADR5ow==
dependencies:
chalk "^4.0.0"
debug "^4.3.4"
dotenv "~16.4.5"
dotenv-expand "~11.0.6"
getenv "^2.0.0"
"@expo/fingerprint@0.11.11":
version "0.11.11"
resolved "https://registry.yarnpkg.com/@expo/fingerprint/-/fingerprint-0.11.11.tgz#ae644d4ff7dc26d1ffecce376a5209d001c49331"
@@ -2160,6 +2235,14 @@
json5 "^2.2.3"
write-file-atomic "^2.3.0"
"@expo/json-file@^9.1.5", "@expo/json-file@~9.1.3", "@expo/json-file@~9.1.5":
version "9.1.5"
resolved "https://registry.yarnpkg.com/@expo/json-file/-/json-file-9.1.5.tgz#7d7b2dc4990dc2c2de69a571191aba984b7fb7ed"
integrity sha512-prWBhLUlmcQtvN6Y7BpW2k9zXGd3ySa3R6rAguMJkp1z22nunLN64KYTUWfijFlprFoxm9r2VNnGkcbndAlgKA==
dependencies:
"@babel/code-frame" "~7.10.4"
json5 "^2.2.3"
"@expo/metro-config@0.19.12", "@expo/metro-config@~0.19.12":
version "0.19.12"
resolved "https://registry.yarnpkg.com/@expo/metro-config/-/metro-config-0.19.12.tgz#ce6d8dec9aab790874cd0299a64968f74267db1c"
@@ -2224,6 +2307,15 @@
base64-js "^1.2.3"
xmlbuilder "^14.0.0"
"@expo/plist@^0.3.3", "@expo/plist@^0.3.5":
version "0.3.5"
resolved "https://registry.yarnpkg.com/@expo/plist/-/plist-0.3.5.tgz#11913c64951936101529cb26d7260ef16970fc31"
integrity sha512-9RYVU1iGyCJ7vWfg3e7c/NVyMFs8wbl+dMWZphtFtsqyN9zppGREU3ctlD3i8KUE0sCUTVnLjCWr+VeUIDep2g==
dependencies:
"@xmldom/xmldom" "^0.8.8"
base64-js "^1.2.3"
xmlbuilder "^15.1.1"
"@expo/prebuild-config@~8.2.0":
version "8.2.0"
resolved "https://registry.yarnpkg.com/@expo/prebuild-config/-/prebuild-config-8.2.0.tgz#eeca7c58000bacf4e3e60c6953261f78405eedbc"
@@ -4860,6 +4952,11 @@
resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.13.tgz#ff34942667a4e19a9f4a0996a76814daac364cf3"
integrity sha512-lm2GW5PkosIzccsaZIz7tp8cPADSIlIHWDFTR1N0SzfinhhYgeIQjFMz4rYzanCScr3DqQLeomUDArp6MWKm+g==
"@yarnpkg/lockfile@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31"
integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==
abab@^2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
@@ -5609,7 +5706,7 @@ cacache@^18.0.2:
tar "^6.1.11"
unique-filename "^3.0.0"
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6"
integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==
@@ -5625,7 +5722,17 @@ call-bind@^1.0.0, call-bind@^1.0.2:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
call-bound@^1.0.2:
call-bind@^1.0.8:
version "1.0.8"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c"
integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==
dependencies:
call-bind-apply-helpers "^1.0.0"
es-define-property "^1.0.0"
get-intrinsic "^1.2.4"
set-function-length "^1.2.2"
call-bound@^1.0.2, call-bound@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a"
integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==
@@ -5804,7 +5911,7 @@ ci-info@^2.0.0:
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46"
integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==
ci-info@^3.2.0, ci-info@^3.3.0:
ci-info@^3.2.0, ci-info@^3.3.0, ci-info@^3.7.0:
version "3.9.0"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4"
integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==
@@ -6404,6 +6511,15 @@ defaults@^1.0.3:
dependencies:
clone "^1.0.2"
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
define-lazy-prop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
@@ -6789,7 +6905,7 @@ es-abstract@^1.19.0, es-abstract@^1.20.4:
unbox-primitive "^1.0.2"
which-typed-array "^1.1.9"
es-define-property@^1.0.1:
es-define-property@^1.0.0, es-define-property@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa"
integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==
@@ -7229,6 +7345,14 @@ expo-clipboard@~7.0.1:
resolved "https://registry.yarnpkg.com/expo-clipboard/-/expo-clipboard-7.0.1.tgz#31d61270e77a37d2a6b7ae9abf79e060497ef43b"
integrity sha512-rqYk0+WoqitPcPKxmMxSpLonX1E5Ije3LBYfnYMbH3xU5Gr8EAH9QnOWOi4BgahUPvcot6nbFEnx+DqARrmxKQ==
expo-constants@^17.0.2:
version "17.1.7"
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-17.1.7.tgz#35194c1cef51f1ea756333418f1e077be79a012b"
integrity sha512-byBjGsJ6T6FrLlhOBxw4EaiMXrZEn/MlUYIj/JAd+FS7ll5X/S4qVRbIimSJtdW47hXMq0zxPfJX6njtA56hHA==
dependencies:
"@expo/config" "~11.0.12"
"@expo/env" "~1.0.7"
expo-constants@~17.0.3, expo-constants@~17.0.5, expo-constants@~17.0.8:
version "17.0.8"
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-17.0.8.tgz#d7a21ec6f1f4834ea25aa645be20292ef99c0b81"
@@ -7299,7 +7423,7 @@ expo-keep-awake@~14.0.3:
resolved "https://registry.yarnpkg.com/expo-keep-awake/-/expo-keep-awake-14.0.3.tgz#74c91b68effdb6969bc1e8371621aad90386cfbf"
integrity sha512-6Jh94G6NvTZfuLnm2vwIpKe3GdOiVBuISl7FI8GqN0/9UOg9E0WXXp5cDcfAG8bn80RfgLJS8P7EPUGTZyOvhg==
expo-linking@~7.0.3:
expo-linking@~7.0.2, expo-linking@~7.0.5:
version "7.0.5"
resolved "https://registry.yarnpkg.com/expo-linking/-/expo-linking-7.0.5.tgz#6f583c636a3cc29f02d67a1550b21f8e636fe2af"
integrity sha512-3KptlJtcYDPWohk0MfJU75MJFh2ybavbtcSd84zEPfw9s1q3hjimw3sXnH03ZxP54kiEWldvKmmnGcVffBDB1g==
@@ -7360,6 +7484,15 @@ expo-secure-store@~14.0.0:
resolved "https://registry.yarnpkg.com/expo-secure-store/-/expo-secure-store-14.0.1.tgz#8953d5966430f5ff262f4d99e7551205870078d7"
integrity sha512-QUS+j4+UG4jRQalgnpmTvvrFnMVLqPiUZRzYPnG3+JrZ5kwVW2w6YS3WWerPoR7C6g3y/a2htRxRSylsDs+TaQ==
expo-share-intent@^3.2.3:
version "3.2.3"
resolved "https://registry.yarnpkg.com/expo-share-intent/-/expo-share-intent-3.2.3.tgz#65a67ba3bc511c7080ceb27e5b569ed54b656790"
integrity sha512-U0KxSeXv3f8yirYOMcYQJRXakE3uVZVEGXvujZzMdYbwHnMUKf02EJqMLkeK4xRwAfdkiQB7V8AAjy+4RAdIqg==
dependencies:
"@expo/config-plugins" "^9.0.9"
expo-constants "^17.0.2"
expo-linking "~7.0.2"
expo-splash-screen@~0.29.18:
version "0.29.24"
resolved "https://registry.yarnpkg.com/expo-splash-screen/-/expo-splash-screen-0.29.24.tgz#4e5f6d576d3fbb37c5e3e4ee6d3f3b3ece350f75"
@@ -7614,6 +7747,13 @@ find-up@^5.0.0:
locate-path "^6.0.0"
path-exists "^4.0.0"
find-yarn-workspace-root@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd"
integrity sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==
dependencies:
micromatch "^4.0.2"
flat-cache@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11"
@@ -7827,7 +7967,7 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3:
has "^1.0.3"
has-symbols "^1.0.3"
get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01"
integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==
@@ -7898,6 +8038,11 @@ getenv@^1.0.0:
resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31"
integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==
getenv@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/getenv/-/getenv-2.0.0.tgz#b1698c7b0f29588f4577d06c42c73a5b475c69e0"
integrity sha512-VilgtJj/ALgGY77fiLam5iD336eSWi96Q15JSAG1zi8NRBysm3LXKdGnHb4m5cuyxvOLQQKWpBZAT6ni4FI2iQ==
gifwrap@^0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.10.1.tgz#9ed46a5d51913b482d4221ce9c727080260b681e"
@@ -8092,6 +8237,13 @@ has-property-descriptors@^1.0.0:
dependencies:
get-intrinsic "^1.1.1"
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0"
@@ -9392,6 +9544,17 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
json-stable-stringify@^1.0.2:
version "1.3.0"
resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.3.0.tgz#8903cfac42ea1a0f97f35d63a4ce0518f0cc6a70"
integrity sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==
dependencies:
call-bind "^1.0.8"
call-bound "^1.0.4"
isarray "^2.0.5"
jsonify "^0.0.1"
object-keys "^1.1.1"
json5@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593"
@@ -9429,6 +9592,11 @@ jsonfile@^6.0.1:
optionalDependencies:
graceful-fs "^4.1.6"
jsonify@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978"
integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==
"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz#76b3e6e6cece5c69d49a5792c3d01bd1a0cdc7ea"
@@ -9452,6 +9620,13 @@ kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
klaw-sync@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c"
integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==
dependencies:
graceful-fs "^4.1.11"
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
@@ -10028,6 +10203,14 @@ micro@^10.0.1:
content-type "1.0.4"
raw-body "2.4.1"
micromatch@^4.0.2, micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies:
braces "^3.0.3"
picomatch "^2.3.1"
micromatch@^4.0.4:
version "4.0.5"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
@@ -10036,14 +10219,6 @@ micromatch@^4.0.4:
braces "^3.0.2"
picomatch "^2.3.1"
micromatch@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202"
integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==
dependencies:
braces "^3.0.3"
picomatch "^2.3.1"
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
@@ -10616,7 +10791,7 @@ onetime@^5.1.2:
dependencies:
mimic-fn "^2.1.0"
open@^7.0.3:
open@^7.0.3, open@^7.4.2:
version "7.4.2"
resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321"
integrity sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==
@@ -10676,6 +10851,11 @@ ora@^3.4.0:
strip-ansi "^5.2.0"
wcwidth "^1.0.1"
os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==
p-finally@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
@@ -10822,6 +11002,27 @@ partial-json@0.1.7:
resolved "https://registry.yarnpkg.com/partial-json/-/partial-json-0.1.7.tgz#b735a89edb3e25f231a3c4caeaae71dc9f578605"
integrity sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==
patch-package@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-8.0.0.tgz#d191e2f1b6e06a4624a0116bcb88edd6714ede61"
integrity sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==
dependencies:
"@yarnpkg/lockfile" "^1.1.0"
chalk "^4.1.2"
ci-info "^3.7.0"
cross-spawn "^7.0.3"
find-yarn-workspace-root "^2.0.0"
fs-extra "^9.0.0"
json-stable-stringify "^1.0.2"
klaw-sync "^6.0.0"
minimist "^1.2.6"
open "^7.4.2"
rimraf "^2.6.3"
semver "^7.5.3"
slash "^2.0.0"
tmp "^0.0.33"
yaml "^2.2.2"
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
@@ -11922,6 +12123,13 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@^2.6.3:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -12146,6 +12354,18 @@ set-blocking@^2.0.0:
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==
set-function-length@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
@@ -12294,6 +12514,11 @@ sisteransi@^1.0.5:
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -12932,6 +13157,13 @@ tinycolor2@^1.6.0:
resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
tmp@^0.0.33:
version "0.0.33"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
dependencies:
os-tmpdir "~1.0.2"
tmpl@1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
@@ -13720,6 +13952,11 @@ yaml@^1.10.0:
resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==
yaml@^2.2.2:
version "2.8.1"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.1.tgz#1870aa02b631f7e8328b93f8bc574fac5d6c4d79"
integrity sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==
yaml@^2.3.4:
version "2.8.0"
resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.8.0.tgz#15f8c9866211bdc2d3781a0890e44d4fa1a5fff6"