Skip to content
Draft
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
189 changes: 189 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 7 additions & 28 deletions apps/expo-glyphnet/src/features/encode/EncodePanel.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as FileSystem from "expo-file-system";
import { Directory, File, Paths } from "expo-file-system";
import * as MediaLibrary from "expo-media-library";
import * as Print from "expo-print";
import { useMemo, useState } from "react";
Expand All @@ -7,24 +7,6 @@ import { SvgXml } from "react-native-svg";
import { scannerAdapter } from "@/adapters/scanner";
import { Pressable, Text, TextInput, View } from "@/tw";

function getWritableBaseDir(): string | null {
const fsAny = FileSystem as unknown as {
documentDirectory?: string | null;
cacheDirectory?: string | null;
Paths?: {
document?: { uri?: string };
cache?: { uri?: string };
};
};
return (
fsAny.documentDirectory ??
fsAny.cacheDirectory ??
fsAny.Paths?.document?.uri ??
fsAny.Paths?.cache?.uri ??
null
);
}

export function EncodePanel() {
const [payload, setPayload] = useState("hello glyphnet");
const [svgPreview, setSvgPreview] = useState("");
Expand Down Expand Up @@ -63,15 +45,12 @@ export function EncodePanel() {
return;
}
try {
const dir = getWritableBaseDir();
if (!dir) {
setActionMessage("Unable to access local storage.");
return;
}
const uri = `${dir}glyphnet-${Date.now()}.svg`;
await FileSystem.writeAsStringAsync(uri, svgPreview, {
encoding: FileSystem.EncodingType.UTF8,
});
const exportDir = new Directory(Paths.document, "glyphnet-exports");
exportDir.create({ idempotent: true, intermediates: true });
const file = new File(exportDir, `glyphnet-${Date.now()}.svg`);
file.create({ overwrite: true, intermediates: true });
file.write(svgPreview, { encoding: "utf8" });
const uri = file.uri;
Comment on lines +48 to +53

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print the relevant section around the export + media-library save call
FILE="apps/expo-glyphnet/src/features/encode/EncodePanel.tsx"
echo "== File = $FILE =="
test -f "$FILE" && nl -ba "$FILE" | sed -n '1,140p' || { echo "File not found"; exit 1; }

# Specifically extract the export block + any nearby MediaLibrary usage
nl -ba "$FILE" | sed -n '35,120p' | sed -n '1,120p' >/tmp/snippet_35_120.txt
echo "== Extract export/media-library vicinity (lines 35-120) =="
cat /tmp/snippet_35_120.txt

Repository: TriForMine/glyphnet

Length of output: 205


🌐 Web query:

expo-media-library saveToLibraryAsync localUri accepted file types image video svg

💡 Result:

The expo-media-library saveToLibraryAsync function is designed to save images and videos to the user's device media library [1][2]. Regarding the file types: Images and Videos: The function natively supports standard image and video file formats, such as JPEG, PNG, and MP4 [3][4][5]. Ensure your localUri points to a valid file path, typically starting with file:// on Android [5]. SVG Files: The MediaLibrary API does not support saving SVG files directly to the device's photo/media library. Standard mobile operating system media galleries (iOS Photos and Android Gallery/Google Photos) are designed for raster images and video files [6]. If you need to save an SVG to the media library, you must first convert or export it to a supported raster format (like PNG or JPEG) within your application using a library like expo-image-manipulator or an image processing tool [6]. Common Troubleshooting: - Ensure you have the necessary permissions requested and granted (MEDIA_LIBRARY/CAMERA_ROLL) [3][4][5]. - Verify that your Info.plist (iOS) includes the required NSPhotoLibraryAddUsageDescription key [5]. - If you encounter a "This file type is not supported yet" error, ensure you are using a recent version of the expo-media-library package, as past issues related to file type recognition (especially for videos on iOS) have been addressed in recent updates [4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Find MediaLibrary.saveToLibraryAsync occurrences in the repo to understand branching/usage patterns
rg -n "MediaLibrary\.saveToLibraryAsync|saveToLibraryAsync\(" apps/expo-glyphnet/src -S

Repository: TriForMine/glyphnet

Length of output: 175


🏁 Script executed:

#!/bin/bash
set -euo pipefail
# Check if EncodePanel.tsx does any rasterization/conditional handling for svg vs png/jpg
FILE="apps/expo-glyphnet/src/features/encode/EncodePanel.tsx"
rg -n "svg|png|jpeg|jpg|raster|rasterize|MediaLibrary" "$FILE" -S

Repository: TriForMine/glyphnet

Length of output: 1035


🏁 Script executed:

#!/bin/bash
set -euo pipefail
FILE="apps/expo-glyphnet/src/features/encode/EncodePanel.tsx"

echo "== Head (imports/state hooks) =="
awk 'NR<=120 {printf "%4d:%s\n", NR, $0}' "$FILE" | sed -n '1,120p'

echo
echo "== Export/save section (approx 35-105) =="
awk 'NR>=35 && NR<=115 {printf "%4d:%s\n", NR, $0}' "$FILE"

echo
echo "== Search nearby for fallback APIs =="
rg -n "shareAsync|Sharing|FileSystem|expo-sharing|writeAsStringAsync|DocumentDirectory|documentDirectory|saveToLibraryAsync|catch|mimeType" "$FILE" -n -S

Repository: TriForMine/glyphnet

Length of output: 8143


🌐 Web query:

site:docs.expo.dev media-library saveToLibraryAsync svg

💡 Result:

In Expo/React Native, MediaLibrary.saveToLibraryAsync(localUri) saves a file (image or video) from a local URI into the user’s media library, but it is not documented as supporting SVG directly. What the official docs require 1) The argument must be an image/video file URI and “must contain an extension” [1]. 2) On Android, localUri “must be a local path” and “must start with file:///” [1]. 3) The saveToLibraryAsync API expects an image or video file: it is described as saving “the image or video file” at localUri to the user’s media library [1]. Implication for SVG - Because the API is documented specifically for image/video files (and does not call out SVG as a supported file type for saving), you should not assume that passing a.svg URI will work reliably. The docs only guarantee support based on being an image/video file with an extension [1]. - If your goal is to persist an SVG “drawing” to the media library, a robust approach is to render the SVG to a raster format (e.g., PNG) and then save that raster file via saveToLibraryAsync. If you’re using the newer expo-media-library API - Expo notes that saveToLibraryAsync is not available in the “new API”; the replacement is Asset.create(localUri), which saves the file and returns an Asset instance [2]. You’d still apply the same basic rule: provide a local URI to the file you want saved, with an extension as required by the underlying file-based approach [1][2]. Summary - Use MediaLibrary.saveToLibraryAsync(localUri) with a local file URI (Android: file:///...) that points to an image/video file with an extension [1]. - SVG is not explicitly documented as supported for saving via saveToLibraryAsync, so treat it as unsupported/uncertain and convert SVG to PNG/JPEG first if you need it saved to the gallery.

Citations:


Avoid calling MediaLibrary.saveToLibraryAsync with the generated .svg file

saveSvg writes glyphnet-${Date.now()}.svg to the document directory, then (when permission is granted) calls MediaLibrary.saveToLibraryAsync(uri) on that .svg URI. saveToLibraryAsync is intended for image/video files, and SVG support for direct media-library saving isn’t documented—so the “saved to library” path is unreliable. Convert the SVG to PNG/JPEG before saving, or skip the media-library step for SVG and go straight to the share/app-storage fallback. (docs.expo.dev)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/expo-glyphnet/src/features/encode/EncodePanel.tsx` around lines 48 - 53,
The saveSvg flow writes an SVG file and then calls
MediaLibrary.saveToLibraryAsync on its URI, but MediaLibrary targets
images/videos and may not support SVGs; update the saveSvg logic (the function
that creates exportDir, file, and uses file.uri and
MediaLibrary.saveToLibraryAsync) to detect SVG output and avoid calling
MediaLibrary.saveToLibraryAsync for .svg files—either convert the SVG to a
raster image (PNG/JPEG) before calling MediaLibrary.saveToLibraryAsync, or skip
the media-library path and fall back directly to the share or
app-storage/save-to-documents flow for SVGs; ensure you reference the created
File (file / file.uri) and the MediaLibrary.saveToLibraryAsync call when making
the change.

let savedToLibrary = false;
try {
const perm = await MediaLibrary.requestPermissionsAsync();
Expand Down
Loading
Loading