mirror of
https://github.com/inaturalist/iNaturalistReactNative.git
synced 2025-12-23 22:18:36 -05:00
922 share sheet changes (#3129)
* Allow 500 photos in image picker
* Allow 500 photos from share extension
* Basic React share sheet setup
Following the setup here: f5805e9208/SHARE_EXTENSION_VIEW.md
* Basic ShareSheet React component
* Update ShareSheet.tsx
* Update ShareSheet.tsx
This commit is contained in:
5
index.share.js
Normal file
5
index.share.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
import { AppRegistry } from "react-native";
|
||||||
|
|
||||||
|
import ShareSheet from "./src/components/ShareSheet/ShareSheet";
|
||||||
|
|
||||||
|
AppRegistry.registerComponent( "ShareMenuModuleComponent", () => ShareSheet );
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
<!--Share View Controller-->
|
<!--Share View Controller-->
|
||||||
<scene sceneID="ceB-am-kn3">
|
<scene sceneID="ceB-am-kn3">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
|
<viewController id="j1y-V4-xli" customClass="ReactShareViewController" customModule="iNaturalistReactNative-ShareExtension" customModuleProvider="target" sceneMemberID="viewController">
|
||||||
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<key>NSExtensionActivationRule</key>
|
<key>NSExtensionActivationRule</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||||
<integer>20</integer>
|
<integer>500</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSExtensionMainStoryboard</key>
|
<key>NSExtensionMainStoryboard</key>
|
||||||
@@ -21,5 +21,31 @@
|
|||||||
<key>NSExtensionPointIdentifier</key>
|
<key>NSExtensionPointIdentifier</key>
|
||||||
<string>com.apple.share-services</string>
|
<string>com.apple.share-services</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>ReactShareViewBackgroundColor</key>
|
||||||
|
<dict>
|
||||||
|
<key>Red</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Green</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Blue</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Alpha</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>Transparent</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSExceptionDomains</key>
|
||||||
|
<dict>
|
||||||
|
<key>localhost</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExceptionAllowsInsecureHTTPLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//
|
#import <React/RCTBridge.h>
|
||||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
#import <React/RCTBundleURLProvider.h>
|
||||||
//
|
#import <React/RCTBridgeDelegate.h>
|
||||||
|
#import <React/RCTRootView.h>
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
8F1AC6772BC1B610002F994B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */; };
|
8F1AC6772BC1B610002F994B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */; };
|
||||||
8F1AC6792BC1B610002F994B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */; };
|
8F1AC6792BC1B610002F994B /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */; };
|
||||||
8F346E4A2CF6912700CED7B4 /* geomodel.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = 8F346E492CF6912700CED7B4 /* geomodel.mlmodel */; };
|
8F346E4A2CF6912700CED7B4 /* geomodel.mlmodel in Sources */ = {isa = PBXBuildFile; fileRef = 8F346E492CF6912700CED7B4 /* geomodel.mlmodel */; };
|
||||||
|
8FA933AD2E99522900179553 /* ReactShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8FA933AC2E99522900179553 /* ReactShareViewController.swift */; };
|
||||||
A5C00A8934ED4A48A1495179 /* INatIcon.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0972395C34134C71A54A2A5D /* INatIcon.ttf */; };
|
A5C00A8934ED4A48A1495179 /* INatIcon.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0972395C34134C71A54A2A5D /* INatIcon.ttf */; };
|
||||||
AE4DC81B3A87484CB3FD6750 /* Lato-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4B0AEEF6CA584BCF9880EB35 /* Lato-Regular.ttf */; };
|
AE4DC81B3A87484CB3FD6750 /* Lato-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 4B0AEEF6CA584BCF9880EB35 /* Lato-Regular.ttf */; };
|
||||||
E5DFC1C6FBFA45739CE91C69 /* Lato-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 69DF855D92EA4ADFB73B47F1 /* Lato-MediumItalic.ttf */; };
|
E5DFC1C6FBFA45739CE91C69 /* Lato-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 69DF855D92EA4ADFB73B47F1 /* Lato-MediumItalic.ttf */; };
|
||||||
@@ -92,6 +93,7 @@
|
|||||||
8C2D97D72EED451C887998A8 /* Lato-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Lato-BoldItalic.ttf"; path = "../assets/fonts/Lato-BoldItalic.ttf"; sourceTree = "<group>"; };
|
8C2D97D72EED451C887998A8 /* Lato-BoldItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Lato-BoldItalic.ttf"; path = "../assets/fonts/Lato-BoldItalic.ttf"; sourceTree = "<group>"; };
|
||||||
8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
8F1AC6762BC1B610002F994B /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||||
8F346E492CF6912700CED7B4 /* geomodel.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = geomodel.mlmodel; sourceTree = "<group>"; };
|
8F346E492CF6912700CED7B4 /* geomodel.mlmodel */ = {isa = PBXFileReference; lastKnownFileType = file.mlmodel; path = geomodel.mlmodel; sourceTree = "<group>"; };
|
||||||
|
8FA933AC2E99522900179553 /* ReactShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ReactShareViewController.swift; path = "../node_modules/react-native-share-menu/ios/ReactShareViewController.swift"; sourceTree = SOURCE_ROOT; };
|
||||||
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
|
||||||
F15C1390617A309CE0A194B2 /* Pods_iNaturalistReactNative_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iNaturalistReactNative_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
F15C1390617A309CE0A194B2 /* Pods_iNaturalistReactNative_ShareExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iNaturalistReactNative_ShareExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
@@ -202,6 +204,7 @@
|
|||||||
8B65ED2C29F575C10054CCEF /* iNaturalistReactNative-ShareExtension */ = {
|
8B65ED2C29F575C10054CCEF /* iNaturalistReactNative-ShareExtension */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
8FA933AC2E99522900179553 /* ReactShareViewController.swift */,
|
||||||
8B65ED3C29F576D00054CCEF /* iNaturalistReactNative-ShareExtension.entitlements */,
|
8B65ED3C29F576D00054CCEF /* iNaturalistReactNative-ShareExtension.entitlements */,
|
||||||
8B65ED3A29F575FE0054CCEF /* ShareViewController.swift */,
|
8B65ED3A29F575FE0054CCEF /* ShareViewController.swift */,
|
||||||
8B65ED2F29F575C10054CCEF /* MainInterface.storyboard */,
|
8B65ED2F29F575C10054CCEF /* MainInterface.storyboard */,
|
||||||
@@ -260,6 +263,7 @@
|
|||||||
8B65ED2829F575C10054CCEF /* Frameworks */,
|
8B65ED2829F575C10054CCEF /* Frameworks */,
|
||||||
8B65ED2929F575C10054CCEF /* Resources */,
|
8B65ED2929F575C10054CCEF /* Resources */,
|
||||||
CBBE96E94BCFC337E2A3EDB6 /* [CP] Copy Pods Resources */,
|
CBBE96E94BCFC337E2A3EDB6 /* [CP] Copy Pods Resources */,
|
||||||
|
8F0FF30C2E9AF08F005DCE05 /* Bundle React Native code and images */,
|
||||||
);
|
);
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
@@ -397,6 +401,24 @@
|
|||||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iNaturalistReactNative/Pods-iNaturalistReactNative-frameworks.sh\"\n";
|
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iNaturalistReactNative/Pods-iNaturalistReactNative-frameworks.sh\"\n";
|
||||||
showEnvVarsInLog = 0;
|
showEnvVarsInLog = 0;
|
||||||
};
|
};
|
||||||
|
8F0FF30C2E9AF08F005DCE05 /* Bundle React Native code and images */ = {
|
||||||
|
isa = PBXShellScriptBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
);
|
||||||
|
inputFileListPaths = (
|
||||||
|
);
|
||||||
|
inputPaths = (
|
||||||
|
);
|
||||||
|
name = "Bundle React Native code and images";
|
||||||
|
outputFileListPaths = (
|
||||||
|
);
|
||||||
|
outputPaths = (
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
shellPath = /bin/sh;
|
||||||
|
shellScript = "export ENTRY_FILE=index.share.js\n\nset -e\n\nWITH_ENVIRONMENT=\"$REACT_NATIVE_PATH/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"$REACT_NATIVE_PATH/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
|
||||||
|
};
|
||||||
987B044B8ED1BE214203D222 /* [CP] Copy Pods Resources */ = {
|
987B044B8ED1BE214203D222 /* [CP] Copy Pods Resources */ = {
|
||||||
isa = PBXShellScriptBuildPhase;
|
isa = PBXShellScriptBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
@@ -472,6 +494,7 @@
|
|||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
8B65ED3B29F575FE0054CCEF /* ShareViewController.swift in Sources */,
|
8B65ED3B29F575FE0054CCEF /* ShareViewController.swift in Sources */,
|
||||||
|
8FA933AD2E99522900179553 /* ReactShareViewController.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import { useLayoutPrefs } from "sharedHooks";
|
|||||||
import useExitObservationsFlow from "sharedHooks/useExitObservationFlow";
|
import useExitObservationsFlow from "sharedHooks/useExitObservationFlow";
|
||||||
import useStore from "stores/useStore";
|
import useStore from "stores/useStore";
|
||||||
|
|
||||||
const MAX_PHOTOS_ALLOWED = 20;
|
const MAX_PHOTOS_ALLOWED = 500;
|
||||||
const FROM_AICAMERA_MAX_PHOTOS_ALLOWED = 1;
|
const FROM_AICAMERA_MAX_PHOTOS_ALLOWED = 1;
|
||||||
|
|
||||||
const PhotoLibrary = ( ): Node => {
|
const PhotoLibrary = ( ): Node => {
|
||||||
|
|||||||
86
src/components/ShareSheet/ShareSheet.tsx
Normal file
86
src/components/ShareSheet/ShareSheet.tsx
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Fellow developers: This is the component that is rendered when the share extension is opened.
|
||||||
|
// It uses a separate React instance and entry point that is registered in index.share.js
|
||||||
|
// It is not set up to use anything from the main app, like nativewind or styled components.
|
||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import {
|
||||||
|
Pressable, StyleSheet, Text, View
|
||||||
|
} from "react-native";
|
||||||
|
import { ShareMenuReactView } from "react-native-share-menu";
|
||||||
|
|
||||||
|
interface ButtonProps {
|
||||||
|
onPress: () => void;
|
||||||
|
title: string;
|
||||||
|
style?: object;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Button = ( { onPress, title, style }: ButtonProps ) => (
|
||||||
|
<Pressable accessibilityRole="button" onPress={onPress}>
|
||||||
|
{/* eslint-disable-next-line no-use-before-define */}
|
||||||
|
<Text style={[styles.button, style]}>{title}</Text>
|
||||||
|
</Pressable>
|
||||||
|
);
|
||||||
|
|
||||||
|
const ShareSheet = () => {
|
||||||
|
const [sharedData, setSharedData] = useState( [] );
|
||||||
|
|
||||||
|
useEffect( () => {
|
||||||
|
// @ts-expect-error data has any type here, but the actual type should come from the library
|
||||||
|
ShareMenuReactView.data().then( ( { data } ) => {
|
||||||
|
setSharedData( data );
|
||||||
|
} );
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
const {
|
||||||
|
container, text, buttonGroup, destructive
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
} = styles;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View style={container}>
|
||||||
|
<Text style={text}>
|
||||||
|
{`Share ${sharedData.length} photos with iNaturalist?`}
|
||||||
|
</Text>
|
||||||
|
<View style={buttonGroup}>
|
||||||
|
<Button
|
||||||
|
title="Yes"
|
||||||
|
onPress={( ) => {
|
||||||
|
ShareMenuReactView.continueInApp( );
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
title="No"
|
||||||
|
onPress={( ) => {
|
||||||
|
ShareMenuReactView.dismissExtension( );
|
||||||
|
}}
|
||||||
|
style={destructive}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const styles = StyleSheet.create( {
|
||||||
|
button: {
|
||||||
|
fontSize: 16,
|
||||||
|
margin: 16
|
||||||
|
},
|
||||||
|
container: {
|
||||||
|
flex: 1,
|
||||||
|
backgroundColor: "white"
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
fontSize: 20,
|
||||||
|
textAlign: "center",
|
||||||
|
margin: 16
|
||||||
|
},
|
||||||
|
buttonGroup: {
|
||||||
|
flexDirection: "row",
|
||||||
|
justifyContent: "space-around",
|
||||||
|
alignItems: "center"
|
||||||
|
},
|
||||||
|
destructive: {
|
||||||
|
color: "red"
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
export default ShareSheet;
|
||||||
Reference in New Issue
Block a user