-
Notifications
You must be signed in to change notification settings - Fork 136
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Custom text and binary attachments in test apps #179
Changes from 12 commits
270aa08
aa6ff68
6125289
f43a4fd
01e74b3
bb32f6d
7522022
d230b62
520105f
1a3c6f5
b3c68e3
3ef0766
88280f9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { AsyncStorage } from 'react-native'; | ||
import RNFS from 'react-native-fs'; | ||
|
||
const TEXT_ATTACHMENT_KEY = 'TEXT_ATTACHMENT_KEY'; | ||
const BINARY_FILENAME_KEY = 'BINARY_FILENAME_KEY'; | ||
const BINARY_FILETYPE_KEY = 'BINARY_FILETYPE_KEY'; | ||
const BINARY_FILESIZE_KEY = 'BINARY_FILESIZE_KEY'; | ||
|
||
const DEFAULT_FILENAME = 'binary.txt'; | ||
const DEFAULT_ENCODING = 'utf8'; | ||
|
||
export default class AttachmentsProvider { | ||
static async saveTextAttachment(value) { | ||
await AsyncStorage.setItem(TEXT_ATTACHMENT_KEY, value); | ||
} | ||
|
||
static async getTextAttachment() { | ||
return getItemFromStorage(TEXT_ATTACHMENT_KEY, 'hello'); | ||
} | ||
|
||
static async saveBinaryAttachment(name, data, type, size) { | ||
AsyncStorage.setItem(BINARY_FILENAME_KEY, name); | ||
AsyncStorage.setItem(BINARY_FILETYPE_KEY, type); | ||
AsyncStorage.setItem(BINARY_FILESIZE_KEY, size); | ||
saveFileInDocumentsFolder(DEFAULT_FILENAME, data); | ||
} | ||
|
||
static async getBinaryAttachment() { | ||
const path = `${RNFS.DocumentDirectoryPath}/${DEFAULT_FILENAME}`; | ||
let contents = ''; | ||
try { | ||
contents = await RNFS.readFile(path, DEFAULT_ENCODING); | ||
} catch (error) { | ||
console.error('Error while reading binary attachment file'); | ||
} | ||
return contents; | ||
} | ||
|
||
static async getBinaryName() { | ||
return getItemFromStorage(BINARY_FILENAME_KEY); | ||
} | ||
|
||
static async getBinaryType() { | ||
return getItemFromStorage(BINARY_FILETYPE_KEY); | ||
} | ||
|
||
static async getBinaryAttachmentInfo() { | ||
const fileName = await getItemFromStorage(BINARY_FILENAME_KEY); | ||
const fileSize = await getItemFromStorage(BINARY_FILESIZE_KEY); | ||
return `${fileName} (${fileSize})`; | ||
} | ||
} | ||
|
||
async function getItemFromStorage(key, defaultValue = '') { | ||
try { | ||
return await AsyncStorage.getItem(key); | ||
} catch (error) { | ||
console.error(`Error retrieving item with key: ${key}`); | ||
console.error(error.message); | ||
} | ||
return defaultValue; | ||
} | ||
|
||
async function saveFileInDocumentsFolder(fileName, data) { | ||
const path = `${RNFS.DocumentDirectoryPath}/${fileName}`; | ||
RNFS.writeFile(path, data, DEFAULT_ENCODING) | ||
.then(() => console.log('Binary attachment saved')) | ||
.catch(err => console.error(err.message)); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,25 +9,32 @@ import { | |
StyleSheet, | ||
Text, | ||
View, | ||
TextInput, | ||
ScrollView, | ||
TouchableOpacity | ||
} from 'react-native'; | ||
|
||
import { DialogComponent } from 'react-native-dialog-component'; | ||
import ImagePicker from 'react-native-image-picker'; | ||
|
||
import Crashes from 'appcenter-crashes'; | ||
import { FooClass } from './js/FooClass'; | ||
import SharedStyles from './SharedStyles'; | ||
import AttachmentsProvider from './AttachmentsProvider'; | ||
|
||
export default class CrashesScreen extends Component { | ||
constructor() { | ||
super(); | ||
this.state = { | ||
crashesEnabled: false, | ||
lastSessionStatus: '', | ||
sendStatus: '' | ||
textAttachment: '', | ||
binaryAttachment: '' | ||
}; | ||
this.toggleEnabled = this.toggleEnabled.bind(this); | ||
this.jsCrash = this.jsCrash.bind(this); | ||
this.nativeCrash = this.nativeCrash.bind(this); | ||
this.showFilePicker = this.showFilePicker.bind(this); | ||
} | ||
|
||
async componentDidMount() { | ||
|
@@ -48,6 +55,12 @@ export default class CrashesScreen extends Component { | |
status += JSON.stringify(crashReport, null, 4); | ||
component.setState({ lastSessionStatus: status }); | ||
} | ||
|
||
const textAttachmentValue = await AttachmentsProvider.getTextAttachment(); | ||
component.setState({ textAttachment: textAttachmentValue }); | ||
|
||
const binaryAttachmentValue = await AttachmentsProvider.getBinaryAttachmentInfo(); | ||
component.setState({ binaryAttachment: binaryAttachmentValue }); | ||
} | ||
|
||
async toggleEnabled() { | ||
|
@@ -73,7 +86,6 @@ export default class CrashesScreen extends Component { | |
<Text style={SharedStyles.heading}> | ||
Test Crashes | ||
</Text> | ||
|
||
<Text style={SharedStyles.enabledText}> | ||
Crashes enabled: {this.state.crashesEnabled ? 'yes' : 'no'} | ||
</Text> | ||
|
@@ -82,7 +94,6 @@ export default class CrashesScreen extends Component { | |
toggle | ||
</Text> | ||
</TouchableOpacity> | ||
|
||
<TouchableOpacity onPress={this.jsCrash}> | ||
<Text style={styles.button}> | ||
Crash JavaScript | ||
|
@@ -93,14 +104,103 @@ export default class CrashesScreen extends Component { | |
Crash native code | ||
</Text> | ||
</TouchableOpacity> | ||
<TouchableOpacity onPress={() => { this.dialogComponent.show(); }}> | ||
<Text style={styles.button}> | ||
Set text error attachment | ||
</Text> | ||
</TouchableOpacity> | ||
<Text style={SharedStyles.enabledText}>{'Current value:'}{this.state.textAttachment}</Text> | ||
<TouchableOpacity onPress={this.showFilePicker}> | ||
<Text style={styles.button}> | ||
Select image as binary error attachment | ||
</Text> | ||
</TouchableOpacity> | ||
<Text style={SharedStyles.enabledText}>{'Current value:'}{this.state.binaryAttachment}</Text> | ||
<Text style={styles.lastSessionHeader}>Last session:</Text> | ||
<Text style={styles.lastSessionInfo}> | ||
{this.state.lastSessionStatus} | ||
</Text> | ||
</ScrollView> | ||
{this.getTextAttachmentDialog()} | ||
</View> | ||
); | ||
} | ||
|
||
getTextAttachmentDialog() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I recommend check-in two large image files as part of the TestApp to make testing easier. Due to the error attachment size limit of 1.4 MB on android and 10 MB on ios, I recommend a image < 1.4 MB and another image < 10 MB. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or create two base64 strings instead of check-in binary image files. We can't assume testing devices have such large binary files for testing. |
||
return ( | ||
<DialogComponent | ||
ref={(dialogComponent) => { this.dialogComponent = dialogComponent; }} | ||
width={0.9} | ||
> | ||
<View> | ||
<TextInput | ||
style={{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please refactor all UI styles in this class into |
||
height: 40, borderColor: 'gray', borderWidth: 1, margin: 8 | ||
}} | ||
onChangeText={text => this.setState({ textAttachment: text })} | ||
/> | ||
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'space-between' }}> | ||
<TouchableOpacity | ||
style={{ height: 50 }} | ||
onPress={() => { | ||
AttachmentsProvider.saveTextAttachment(this.state.textAttachment); | ||
this.dialogComponent.dismiss(); | ||
}} | ||
> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
<Text style={styles.button}> | ||
Save | ||
</Text> | ||
</TouchableOpacity> | ||
<TouchableOpacity | ||
style={{ height: 50 }} | ||
onPress={() => { this.dialogComponent.dismiss(); }} | ||
> | ||
<Text style={styles.button}> | ||
Cancel | ||
</Text> | ||
</TouchableOpacity> | ||
</View> | ||
</View> | ||
</DialogComponent> | ||
); | ||
} | ||
|
||
showFilePicker() { | ||
ImagePicker.showImagePicker(null, async (response) => { | ||
if (response.didCancel) { | ||
console.log('User cancelled image picker'); | ||
} else if (response.error) { | ||
console.log('ImagePicker Error: ', response.error); | ||
} else { | ||
AttachmentsProvider.saveBinaryAttachment(getFileName(response), response.data, getFileType(response), getFileSize(response)); | ||
const binaryAttachmentValue = await AttachmentsProvider.getBinaryAttachmentInfo(); | ||
this.setState({ binaryAttachment: binaryAttachmentValue }); | ||
} | ||
}); | ||
|
||
function getFileName(response) { | ||
return response.fileName != null ? response.fileName : 'binary.jpeg'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use
|
||
} | ||
|
||
function getFileType(response) { | ||
return response.type != null ? response.type : 'image/jpeg'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here, see my other comment. |
||
} | ||
|
||
function getFileSize(response) { | ||
const thresh = 1024; | ||
const units = ['KiB', 'MiB', 'GiB']; | ||
let fileSize = response.fileSize; | ||
if (Math.abs(fileSize) < thresh) { | ||
return `${fileSize} B`; | ||
} | ||
let u = -1; | ||
do { | ||
fileSize /= thresh; | ||
++u; | ||
} while (Math.abs(fileSize) >= thresh && u < units.length - 1); | ||
return `${fileSize.toFixed(1)} ${units[u]}`; | ||
} | ||
} | ||
} | ||
|
||
|
||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
styling: use 2 space indentation instead of 4 space