Skip to content

Commit

Permalink
Fix NFT save (#6356)
Browse files Browse the repository at this point in the history
  • Loading branch information
brunobar79 authored Jan 9, 2025
1 parent 9e2a040 commit a206ef4
Show file tree
Hide file tree
Showing 6 changed files with 97 additions and 99 deletions.
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.BLUETOOTH"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,10 @@ const UniqueTokenExpandedStateHeader = ({
} else if (actionKey === AssetActionsEnum.copyTokenID) {
setClipboard(asset.id);
} else if (actionKey === AssetActionsEnum.download) {
saveToCameraRoll(getFullResUrl(asset.image_url));
if (asset?.image_url) {
const fullResUrl = getFullResUrl(asset.image_url);
fullResUrl && saveToCameraRoll(fullResUrl);
}
} else if (actionKey === AssetActionsEnum.hide) {
if (isHiddenAsset) {
removeHiddenToken(asset);
Expand Down
95 changes: 0 additions & 95 deletions src/components/expanded-state/unique-token/saveToCameraRoll.js

This file was deleted.

88 changes: 88 additions & 0 deletions src/components/expanded-state/unique-token/saveToCameraRoll.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CameraRoll } from '@react-native-camera-roll/camera-roll';
import lang from 'i18n-js';
import { PermissionsAndroid, Platform } from 'react-native';
import RNFetchBlob from 'rn-fetch-blob';
import { WrappedAlert as Alert } from '@/helpers/alert';
import { shouldCreateImgixClient } from '@/handlers/imgix';

async function getPermissionAndroid(): Promise<boolean | undefined> {
try {
if (Number(Platform.Version) >= 33) {
return true;
}

const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, {
buttonNegative: lang.t('button.cancel'),
buttonPositive: lang.t('button.ok'),
message: lang.t('expanded_state.unique.save.your_permission_is_required'),
title: lang.t('expanded_state.unique.save.image_download_permission'),
});

if (granted === PermissionsAndroid.RESULTS.GRANTED) {
return true;
}
} catch (e: any) {
alertError(e);
}

return undefined;
}

function alertError(error?: { message?: string }): void {
Alert.alert(
lang.t('expanded_state.unique.save.failed_to_save_image'),
error?.message ? `${error.message}` : '',
[{ text: lang.t('button.ok') }],
{ cancelable: false }
);
}

async function downloadImageAndroid(url: string): Promise<void> {
const granted = await getPermissionAndroid();
if (!granted) {
alertError({
message: lang.t('expanded_state.unique.save.access_to_photo_library_was_denied'),
});
return;
}

const { config } = RNFetchBlob;
const options = {
fileCache: true,
appendExt: 'png',
};

try {
const finalRes = await config(options).fetch('GET', url);
await CameraRoll.saveAsset(finalRes.path(), { type: 'photo' });
} catch (error: any) {
alertError(error);
}
}

async function downloadImageIOS(url: string): Promise<void> {
try {
const res = await RNFetchBlob.config({ fileCache: true, appendExt: 'png' }).fetch('GET', url);
await CameraRoll.saveAsset(res.path(), { type: 'photo' });
} catch (e: any) {
alertError(e);
}
}

const saveToCameraRoll = async (url: string): Promise<void> => {
const staticImgixClient = shouldCreateImgixClient();
if (!staticImgixClient) {
alertError();
return;
}
const url2Download = staticImgixClient?.buildURL(url);

if (Platform.OS === 'android') {
await downloadImageAndroid(url2Download);
} else {
await downloadImageIOS(url2Download);
}
};

export default saveToCameraRoll;
2 changes: 1 addition & 1 deletion src/handlers/imgix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import parse from 'url-parse';
import { isCloudinaryStorageIconLink, signCloudinaryIconUrl } from '@/handlers/cloudinary';
import { logger, RainbowError } from '@/logger';

const shouldCreateImgixClient = (): ImgixClient | null => {
export const shouldCreateImgixClient = (): ImgixClient | null => {
if (typeof domain === 'string' && !!domain.length && typeof secureURLToken === 'string' && !!secureURLToken.length) {
return new ImgixClient({
domain,
Expand Down
5 changes: 3 additions & 2 deletions src/utils/buildRainbowUrl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ export function buildRainbowUrl(asset: UniqueAsset | null, accountENS: string, a
const address = accountENS || accountAddress;
const slug = asset?.collection?.slug;
const assetId = asset?.uniqueId;
const network = asset?.network ? (asset?.network + '_').replace('mainnet', 'ethereum') : '';

const familyString = slug ? `?family=${slug}` : '';
const assetString = slug && assetId?.toString() ? `&nft=${assetId?.toString()}` : '';
const assetString = slug && assetId?.toString() ? `&nft=${network}${assetId?.toString()}` : '';

const url = `${RAINBOW_PROFILES_BASE_URL}/${address}${familyString}${assetString}`;
const url = `${RAINBOW_PROFILES_BASE_URL}/profile/${address}${familyString}${assetString}`;
return url;
}

Expand Down

0 comments on commit a206ef4

Please sign in to comment.