diff --git a/blue_modules/fs.ts b/blue_modules/fs.ts index 6869a8375..18b3af253 100644 --- a/blue_modules/fs.ts +++ b/blue_modules/fs.ts @@ -1,10 +1,10 @@ import LocalQRCode from '@remobile/react-native-qrcode-local-image'; -import { Alert, Linking, PermissionsAndroid, Platform } from 'react-native'; +import { Alert, Linking, Platform } from 'react-native'; import DocumentPicker from 'react-native-document-picker'; import RNFS from 'react-native-fs'; import { launchImageLibrary } from 'react-native-image-picker'; import Share from 'react-native-share'; - +import { request, PERMISSIONS } from 'react-native-permissions'; import presentAlert from '../components/Alert'; import loc from '../loc'; import { isDesktop } from './environment'; @@ -39,6 +39,7 @@ const _shareOpen = async (filePath: string, showShareDialog: boolean = false) => * Writes a file to fs, and triggers an OS sharing dialog, so user can decide where to put this file (share to cloud * or perhabs messaging app). Provided filename should be just a file name, NOT a path */ + export const writeFileAndExport = async function (fileName: string, contents: string, showShareDialog: boolean = true) { const sanitizedFileName = _sanitizeFileName(fileName); if (Platform.OS === 'ios') { @@ -46,44 +47,34 @@ export const writeFileAndExport = async function (fileName: string, contents: st await RNFS.writeFile(filePath, contents); await _shareOpen(filePath, showShareDialog); } else if (Platform.OS === 'android') { - const granted = await PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE, { - title: loc.send.permission_storage_title, - message: loc.send.permission_storage_message, - buttonNeutral: loc.send.permission_storage_later, - buttonNegative: loc._.cancel, - buttonPositive: loc._.ok, - }); - - // In Android 13 no WRITE_EXTERNAL_STORAGE permission is needed - // @see https://stackoverflow.com/questions/76311685/permissionandroid-request-always-returns-never-ask-again-without-any-prompt-r - if (granted === PermissionsAndroid.RESULTS.GRANTED || Platform.Version >= 30) { - const filePath = RNFS.DownloadDirectoryPath + `/${sanitizedFileName}`; - try { - await RNFS.writeFile(filePath, contents); - console.log(`file saved to ${filePath}`); - if (showShareDialog) { - await _shareOpen(filePath); - } else { - presentAlert({ message: loc.formatString(loc.send.file_saved_at_path, { fileName: sanitizedFileName }) }); + const isAndroidVersion33OrAbove = Platform.Version >= 33; + const permissionType = isAndroidVersion33OrAbove ? PERMISSIONS.ANDROID.READ_MEDIA_IMAGES : PERMISSIONS.ANDROID.READ_EXTERNAL_STORAGE; + request(permissionType).then(async result => { + if (result === 'granted') { + const filePath = RNFS.ExternalDirectoryPath + `/${sanitizedFileName}`; + try { + await RNFS.writeFile(filePath, contents); + if (showShareDialog) { + await _shareOpen(filePath); + } else { + presentAlert({ message: loc.formatString(loc.send.file_saved_at_path, { filePath }) }); + } + } catch (e: any) { + presentAlert({ message: e.message }); } - } catch (e: any) { - console.log(e); - } - } else { - console.log('Storage Permission: Denied'); - Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [ - { - text: loc.send.open_settings, - onPress: () => { - Linking.openSettings(); + } else { + Alert.alert(loc.send.permission_storage_title, loc.send.permission_storage_denied_message, [ + { + text: loc.send.open_settings, + onPress: () => { + Linking.openSettings(); + }, + style: 'default', }, - style: 'default', - }, - { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, - ]); - } - } else { - presentAlert({ message: 'Not implemented for this platform' }); + { text: loc._.cancel, onPress: () => {}, style: 'cancel' }, + ]); + } + }); } }; diff --git a/loc/en.json b/loc/en.json index 96ef838dc..9ecf5079e 100644 --- a/loc/en.json +++ b/loc/en.json @@ -178,8 +178,6 @@ "permission_camera_message": "We need your permission to use your camera.", "psbt_sign": "Sign a transaction", "open_settings": "Open Settings", - "permission_storage_later": "Ask me later.", - "permission_storage_message": "BlueWallet needs your permission to access your storage to save this file.", "permission_storage_denied_message": "BlueWallet is unable to save this file. Please open your device settings and enable Storage Permission.", "permission_storage_title": "Storage Access Permission", "psbt_clipboard": "Copy to Clipboard", @@ -193,8 +191,8 @@ "reset_amount": "Reset Amount", "reset_amount_confirm": "Would you like to reset the amount?", "success_done": "Done", - "txSaved": "The transaction file ({filePath}) has been saved in your Downloads folder.", - "file_saved_at_path": "The file ({fileName}) has been saved in your Downloads folder.", + "txSaved": "The transaction file ({filePath}) has been saved.", + "file_saved_at_path": "The file ({filePath}) has been saved.", "cant_send_to_silentpayment_adress": "This wallet cannot send to SilentPayment addresses", "cant_send_to_bip47": "This wallet cannot send to BIP47 payment codes", "cant_find_bip47_notification": "Add this Payment Code to contacts first", diff --git a/screen/settings/SelfTest.js b/screen/settings/SelfTest.js index 51249db02..afca3de6c 100644 --- a/screen/settings/SelfTest.js +++ b/screen/settings/SelfTest.js @@ -11,7 +11,7 @@ import * as BlueElectrum from '../../blue_modules/BlueElectrum'; import * as encryption from '../../blue_modules/encryption'; import * as fs from '../../blue_modules/fs'; import ecc from '../../blue_modules/noble_ecc'; -import { BlueCard, BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents'; +import { BlueLoading, BlueSpacing20, BlueText } from '../../BlueComponents'; import { HDAezeedWallet, HDSegwitBech32Wallet, @@ -22,7 +22,6 @@ import { } from '../../class'; import presentAlert from '../../components/Alert'; import Button from '../../components/Button'; -import SafeArea from '../../components/SafeArea'; import SaveFileButton from '../../components/SaveFileButton'; import loc from '../../loc'; @@ -285,46 +284,42 @@ export default class SelfTest extends Component { } render() { - if (this.state.isLoading) { - return ; - } - return ( - - - - + + - {(() => { - if (this.state.isOk) { - return ( - - - OK - - - {loc.settings.about_selftest_ok} - - ); - } else { - return ( - - - {this.state.errorMessage} - - - ); - } - })()} - - -