Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3,429 changes: 1,680 additions & 1,749 deletions .github/actions/javascript/isDeployChecklistLocked/index.js

Large diffs are not rendered by default.

3,423 changes: 1,677 additions & 1,746 deletions .github/actions/javascript/proposalPoliceComment/index.js

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public List<NativeModule> createNativeModules(
ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();

modules.add(new ShareActionHandlerModule(reactContext));
modules.add(new AppStateTrackerModule(reactContext));
modules.add(new GpsTripServiceModule(reactContext));

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import org.json.JSONObject
data class ShareFileObject(
val content: String,
val mimeType: String?,
val isText: Boolean = false,
) {
override fun toString(): String {
return JSONObject().apply {
put("content", content)
put("mimeType", mimeType)
put("isText", isText)
}.toString()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class TextIntentHandler(private val context: Context) : AbstractIntentHandler()
private fun handleTextPlainIntent(intent: Intent, context: Context) {
var intentTextContent = intent.getStringExtra(Intent.EXTRA_TEXT)
if(intentTextContent != null) {
val shareFileObject = ShareFileObject(intentTextContent, intent.type)
val shareFileObject = ShareFileObject(intentTextContent, intent.type, isText = true)
saveToSharedPreferences(IntentHandlerConstants.shareObjectProperty, shareFileObject.toString())
}
}
Expand Down
6 changes: 0 additions & 6 deletions ios/NewExpensify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
D27CE6B77196EF3EF450EEAC /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 0D3F9E814828D91464DF9D35 /* PrivacyInfo.xcprivacy */; };
DD79042B2792E76D004484B4 /* RCTBootSplash.mm in Sources */ = {isa = PBXBuildFile; fileRef = DD79042A2792E76D004484B4 /* RCTBootSplash.mm */; };
DDCB2E57F334C143AC462B43 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D20D83B0E39BA6D21761E72 /* ExpoModulesProvider.swift */; };
E5A27B912C7F2FA8002C36BF /* RCTShareActionHandlerModule.m in Sources */ = {isa = PBXBuildFile; fileRef = E5A27B902C7F2FA8002C36BF /* RCTShareActionHandlerModule.m */; };
E5A27B9A2C7F427F002C36BF /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5A27B992C7F427F002C36BF /* ShareViewController.swift */; };
E5A27B9D2C7F427F002C36BF /* Base in Resources */ = {isa = PBXBuildFile; fileRef = E5A27B9C2C7F427F002C36BF /* Base */; };
E5A27BA12C7F427F002C36BF /* ShareViewController.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = E5A27B972C7F427F002C36BF /* ShareViewController.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -184,8 +183,6 @@
DCF33E34FFEC48128CDD41D4 /* ExpensifyMono-Bold.otf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "ExpensifyMono-Bold.otf"; path = "../assets/fonts/native/ExpensifyMono-Bold.otf"; sourceTree = "<group>"; };
DD7904292792E76D004484B4 /* RCTBootSplash.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RCTBootSplash.h; path = NewExpensify/RCTBootSplash.h; sourceTree = "<group>"; };
DD79042A2792E76D004484B4 /* RCTBootSplash.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RCTBootSplash.mm; path = NewExpensify/RCTBootSplash.mm; sourceTree = "<group>"; };
E5A27B8F2C7F2F51002C36BF /* RCTShareActionHandlerModule.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTShareActionHandlerModule.h; sourceTree = "<group>"; };
E5A27B902C7F2FA8002C36BF /* RCTShareActionHandlerModule.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTShareActionHandlerModule.m; sourceTree = "<group>"; };
E5A27B972C7F427F002C36BF /* ShareViewController.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = ShareViewController.appex; sourceTree = BUILT_PRODUCTS_DIR; };
E5A27B992C7F427F002C36BF /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
E5A27B9C2C7F427F002C36BF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = "<group>"; };
Expand Down Expand Up @@ -330,8 +327,6 @@
children = (
6E13A8052F51A21100B2FA13 /* LiveActivityExtension.entitlements */,
47347F002DA56FAC00633001 /* NewExpensify-Bridging-Header.h */,
E5A27B8F2C7F2F51002C36BF /* RCTShareActionHandlerModule.h */,
E5A27B902C7F2FA8002C36BF /* RCTShareActionHandlerModule.m */,
0DFC45922C884D7900B56C91 /* RCTShortcutManagerModule.h */,
0DFC45932C884E0A00B56C91 /* RCTShortcutManagerModule.m */,
499B0DA92BE2A1C000CABFB0 /* PrivacyInfo.xcprivacy */,
Expand Down Expand Up @@ -891,7 +886,6 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E5A27B912C7F2FA8002C36BF /* RCTShareActionHandlerModule.m in Sources */,
18D050E0262400AF000D658B /* BridgingFile.swift in Sources */,
0DFC45942C884E0A00B56C91 /* RCTShortcutManagerModule.m in Sources */,
47347EFF2DA5664A00633001 /* AppDelegate.swift in Sources */,
Expand Down
2 changes: 2 additions & 0 deletions ios/NewExpensify/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,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>ShareExtensionAppGroup</key>
<string>group.com.expensify.new</string>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.chat.expensify.backgroundTaskSync</string>
Expand Down
16 changes: 0 additions & 16 deletions ios/RCTShareActionHandlerModule.h

This file was deleted.

129 changes: 0 additions & 129 deletions ios/RCTShareActionHandlerModule.m

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.margelo.nitro.utils

import android.content.Context
import android.graphics.BitmapFactory
import android.media.MediaMetadataRetriever
import android.net.Uri
import android.webkit.MimeTypeMap
import com.margelo.nitro.NitroModules
import com.margelo.nitro.core.Promise
import org.json.JSONObject
import java.io.File
import java.io.IOException
import java.util.Locale

/** Reads the same persisted share intent in standalone and hybrid builds. */
class HybridShareActionHandler : HybridShareActionHandlerSpec() {
override val memorySize: Long = 0L

override fun processFiles(): Promise<Array<SharedFile>> = Promise.parallel {
val context = NitroModules.applicationContext ?: throw IOException("React Native context is unavailable")
// Keep these values aligned with IntentHandlerConstants in
// android/app/src/main/java/com/expensify/chat/intentHandler/IntentHandler.kt.
// This standalone Nitro module cannot import app-level Android code.
val preferences = context.getSharedPreferences("shareActionHandler", Context.MODE_PRIVATE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Shubham's Ai) Nit: "shareActionHandler" / "shareObject" duplicate IntentHandlerConstants (in both App and Mobile-Expensify), which this module can't import. Could you add a comment pointing at the source so the two don't drift?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, addressed. I added a comment identifying IntentHandlerConstants as the source of truth for the duplicated preference file and key, and explaining that the standalone Nitro module cannot import app-level Android code.

val serialized = preferences.getString("shareObject", null) ?: return@parallel emptyArray()
val share = JSONObject(serialized)
val content = share.opt("content") as? String ?: throw IOException("Shared content must be a string")
if (content.isEmpty()) {
throw IOException("Shared content is empty")
}
val file = File(content)
val storedMimeType = share.opt("mimeType")
if (storedMimeType != null && storedMimeType != JSONObject.NULL && storedMimeType !is String) {
throw IOException("Shared MIME type must be a string")
}
var mimeType = (storedMimeType as? String).orEmpty().substringBefore(';').trim().lowercase(Locale.ROOT)
val timestamp = System.currentTimeMillis().toString()

// Older intent handlers did not distinguish literal text from a text file's path.
val isText = if (share.has("isText")) {
share.opt("isText") as? Boolean ?: throw IOException("Shared text discriminator must be a boolean")
} else {
mimeType == "text/plain" && !file.isAbsolute
}
if (isText) {
return@parallel arrayOf(SharedFile("text", content, "txt", timestamp, null))
}

if (!file.isFile || !file.canRead()) {
throw IOException("Shared attachment is missing or unreadable")
}
if (mimeType.isEmpty() || mimeType == "null" || mimeType.endsWith("/*")) {
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(file.extension.lowercase(Locale.ROOT))
?: "application/octet-stream"
}

val aspectRatio = when {
mimeType.startsWith("image/") -> {
val options = BitmapFactory.Options().apply { inJustDecodeBounds = true }
BitmapFactory.decodeFile(content, options)
if (options.outWidth > 0 && options.outHeight > 0) options.outWidth.toDouble() / options.outHeight else null
}
mimeType.startsWith("video/") -> {
val retriever = MediaMetadataRetriever()
try {
retriever.setDataSource(content)
val width = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toDoubleOrNull()
val height = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toDoubleOrNull()
if (width != null && height != null && width > 0 && height > 0) width / height else null
} finally {
retriever.release()
}
}
else -> null

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Shubham's Ai) aspectRatio is now undefined for non-media files on both platforms (previously 0 on Android, 1 on iOS). AttachmentPreview treats it as optional, so this looks fine, but please confirm a PDF share still previews correctly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for flagging. Confirmed by the existing preview implementation: when aspectRatio is undefined, AttachmentPreview defaults it to 1, and the PDF-specific preview branch also explicitly uses aspectRatio: 1. Therefore, PDF preview behavior is unaffected.

}

arrayOf(SharedFile(file.name, Uri.fromFile(file).toString(), mimeType, timestamp, aspectRatio))
}
}
Loading
Loading