[CHORE] Bugsnag logging setup (#1145)

* initial bugsnag setup

* upload sourcemaps to bugsnag during ios-build job

* fix: spacing in config.yml

* add yarn global add react-native

* add separate step: Upload sourcemaps to Bugsnag

* add brew install watchman

* install react-native-cli, remove install watchman

* upload source maps for android build

* add yarn add global react-native react-native-cli for android-build ci job

* add working_directory to android-build

* install npm i -g react-native react-native-cli

* add Install Node step to android-build job

* export path to node to bash_profile

* add step Install React Native CLI to android build job

* use yarn generate-source-maps in ci; exchange firebase log -> bugsnag log

* implement send(toggle) crash reports button

* move BUGSNAG_API_KEY to config file; remove generated source maps files

* unlink bugsnag

* add ios/Pods files connected to Bugsnag; fix ci android build job

* export firebase analytics also from /utils/log

* use `log(e)` instead of `log(error)`

* API Key changes

* pod install

* Fix iOS build

* Simulate error

* lint

* Add navigation

* Use projectRoot

* Revert project root

* - Don't run on forks
- Upload dSYMs

* Remove error sim

* Remove automatic dSYMs upload

* Remove fastlane-plugin-bugsnag
This commit is contained in:
IlarionHalushka 2019-08-23 16:18:47 +03:00 committed by Diego Mello
parent f58f744ee5
commit 59a71ffaef
164 changed files with 12774 additions and 11537 deletions

View File

@ -116,10 +116,26 @@ jobs:
steps: steps:
- checkout - checkout
- run:
name: Install Node 8
command: |
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash
source ~/.nvm/nvm.sh
# https://github.com/creationix/nvm/issues/1394
set +e
nvm install 8
echo 'export PATH="/home/circleci/.nvm/versions/node/v8.16.0/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile
- restore_cache: - restore_cache:
name: Restore NPM cache name: Restore NPM cache
key: node-modules-{{ checksum "yarn.lock" }} key: node-modules-{{ checksum "yarn.lock" }}
- run:
name: Install React Native CLI
command: |
npm i -g react-native-cli
- run: - run:
name: Install NPM modules name: Install NPM modules
command: | command: |
@ -148,12 +164,32 @@ jobs:
fi fi
echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties echo -e "VERSIONCODE=$CIRCLE_BUILD_NUM" >> ./gradle.properties
echo -e "BugsnagAPIKey=$BUGSNAG_KEY" >> ./gradle.properties
- run: - run:
name: Set Google Services name: Set Google Services
command: | command: |
cd android/app
cp google-services.prod.json google-services.json cp google-services.prod.json google-services.json
working_directory: android/app
- run:
name: Upload sourcemaps to Bugsnag
command: |
if [[ $BUGSNAG_KEY ]]; then
yarn generate-source-maps-android
curl https://upload.bugsnag.com/react-native-source-map \
-F apiKey=$BUGSNAG_KEY \
-F appVersionCode=$CIRCLE_BUILD_NUM \
-F dev=false \
-F platform=android \
-F sourceMap=@android-release.bundle.map \
-F bundle=@android-release.bundle
fi
- run:
name: Config variables
command: |
echo -e "export default { BUGSNAG_API_KEY: '$BUGSNAG_KEY' };" > ./config.js
- run: - run:
name: Build Android App name: Build Android App
@ -215,6 +251,7 @@ jobs:
- run: - run:
name: Install NPM modules name: Install NPM modules
command: | command: |
yarn global add react-native react-native-cli
yarn yarn
- run: - run:
@ -229,11 +266,26 @@ jobs:
cp GoogleService-Info.prod.plist GoogleService-Info.plist cp GoogleService-Info.prod.plist GoogleService-Info.plist
working_directory: ios working_directory: ios
- run:
name: Upload sourcemaps to Bugsnag
command: |
if [[ $BUGSNAG_KEY ]]; then
yarn generate-source-maps-ios
curl https://upload.bugsnag.com/react-native-source-map \
-F apiKey=$BUGSNAG_KEY \
-F appBundleVersion=$CIRCLE_BUILD_NUM \
-F dev=false \
-F platform=ios \
-F sourceMap=@ios-release.bundle.map \
-F bundle=@ios-release.bundle
fi
- run: - run:
name: Fastlane Build name: Fastlane Build
no_output_timeout: 1200 no_output_timeout: 1200
command: | command: |
agvtool new-version -all $CIRCLE_BUILD_NUM agvtool new-version -all $CIRCLE_BUILD_NUM
/usr/libexec/PlistBuddy -c "Set BugsnagAPIKey $BUGSNAG_KEY" ./RocketChatRN/Info.plist
if [[ $MATCH_KEYCHAIN_NAME ]]; then if [[ $MATCH_KEYCHAIN_NAME ]]; then
bundle exec fastlane ios release bundle exec fastlane ios release
@ -288,7 +340,7 @@ jobs:
- run: - run:
name: Fastlane Tesflight Upload name: Fastlane Tesflight Upload
command: | command: |
bundle exec fastlane pilot upload --ipa ios/RocketChatRN.ipa --changelog "$(sh ../.circleci/changelog.sh)" bundle exec fastlane ios beta
working_directory: ios working_directory: ios
- save_cache: - save_cache:

View File

@ -1,6 +1,7 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
apply plugin: "io.fabric" apply plugin: "io.fabric"
apply plugin: "com.google.firebase.firebase-perf" apply plugin: "com.google.firebase.firebase-perf"
apply plugin: 'com.bugsnag.android.gradle'
import com.android.build.OutputFile import com.android.build.OutputFile
@ -137,6 +138,7 @@ android {
versionCode VERSIONCODE as Integer versionCode VERSIONCODE as Integer
versionName "1.19.0" versionName "1.19.0"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
} }
signingConfigs { signingConfigs {

View File

@ -5,7 +5,7 @@
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <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_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" /> <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
@ -52,6 +52,9 @@
<data android:mimeType="*/*" /> <data android:mimeType="*/*" />
</intent-filter> </intent-filter>
</activity> </activity>
<meta-data
android:name="com.bugsnag.android.API_KEY"
android:value="${BugsnagAPIKey}" />
</application> </application>
</manifest> </manifest>

View File

@ -24,6 +24,7 @@ buildscript {
classpath 'com.google.gms:google-services:4.2.0' classpath 'com.google.gms:google-services:4.2.0'
classpath 'io.fabric.tools:gradle:1.28.1' classpath 'io.fabric.tools:gradle:1.28.1'
classpath 'com.google.firebase:perf-plugin:1.2.1' classpath 'com.google.firebase:perf-plugin:1.2.1'
classpath 'com.bugsnag:bugsnag-android-gradle-plugin:4.+'
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
@ -50,16 +51,16 @@ allprojects {
} }
} }
// subprojects { subproject -> // subprojects { subproject ->
// afterEvaluate { // afterEvaluate {
// if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) { // if ((subproject.plugins.hasPlugin('android') || subproject.plugins.hasPlugin('android-library'))) {
// android { // android {
// compileSdkVersion 28 // compileSdkVersion 28
// buildToolsVersion "28.0.3" // buildToolsVersion "28.0.3"
// defaultConfig { // defaultConfig {
// targetSdkVersion 28 // targetSdkVersion 28
// } // }
// } // }
// } // }
// } // }
// } // }

View File

@ -22,3 +22,4 @@ org.gradle.jvmargs=-Xmx2048M -XX\:MaxHeapSize\=32g
android.useAndroidX=true android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
VERSIONCODE=999999999 VERSIONCODE=999999999
BugsnagAPIKey=""

View File

@ -18,4 +18,5 @@ if (__DEV__) {
Reactotron.clear(); Reactotron.clear();
console.warn = Reactotron.log; console.warn = Reactotron.log;
console.log = Reactotron.log; console.log = Reactotron.log;
console.disableYellowBox = true;
} }

View File

@ -74,3 +74,4 @@ export const DEEP_LINKING = createRequestTypes('DEEP_LINKING', ['OPEN']);
export const SORT_PREFERENCES = createRequestTypes('SORT_PREFERENCES', ['SET_ALL', 'SET']); export const SORT_PREFERENCES = createRequestTypes('SORT_PREFERENCES', ['SET_ALL', 'SET']);
export const NOTIFICATION = createRequestTypes('NOTIFICATION', ['RECEIVED', 'REMOVE']); export const NOTIFICATION = createRequestTypes('NOTIFICATION', ['RECEIVED', 'REMOVE']);
export const TOGGLE_MARKDOWN = 'TOGGLE_MARKDOWN'; export const TOGGLE_MARKDOWN = 'TOGGLE_MARKDOWN';
export const TOGGLE_CRASH_REPORT = 'TOGGLE_CRASH_REPORT';

View File

@ -0,0 +1,8 @@
import * as types from './actionsTypes';
export function toggleCrashReport(value) {
return {
type: types.TOGGLE_CRASH_REPORT,
payload: value
};
}

View File

@ -311,7 +311,7 @@ class MessageActions extends React.Component {
await RocketChat.reportMessage(actionMessage._id); await RocketChat.reportMessage(actionMessage._id);
Alert.alert(I18n.t('Message_Reported')); Alert.alert(I18n.t('Message_Reported'));
} catch (err) { } catch (err) {
log('err_report_message', err); log(err);
} }
} }
@ -328,7 +328,7 @@ class MessageActions extends React.Component {
await RocketChat.translateMessage(actionMessage, room.autoTranslateLanguage); await RocketChat.translateMessage(actionMessage, room.autoTranslateLanguage);
} }
} catch (err) { } catch (err) {
log('err_toggle_translation', err); log(err);
} }
} }

View File

@ -362,7 +362,7 @@ class MessageBox extends Component {
try { try {
database.create('users', user, true); database.create('users', user, true);
} catch (e) { } catch (e) {
log('err_create_users', e); log(e);
} }
}); });
}); });
@ -504,7 +504,7 @@ class MessageBox extends Component {
try { try {
await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user); await RocketChat.sendFileMessage(rid, fileInfo, tmid, server, user);
} catch (e) { } catch (e) {
log('err_send_media_message', e); log(e);
} }
} }
@ -513,7 +513,7 @@ class MessageBox extends Component {
const image = await ImagePicker.openCamera(this.imagePickerConfig); const image = await ImagePicker.openCamera(this.imagePickerConfig);
this.showUploadModal(image); this.showUploadModal(image);
} catch (e) { } catch (e) {
log('err_take_photo', e); log(e);
} }
} }
@ -522,7 +522,7 @@ class MessageBox extends Component {
const video = await ImagePicker.openCamera(this.videoPickerConfig); const video = await ImagePicker.openCamera(this.videoPickerConfig);
this.showUploadModal(video); this.showUploadModal(video);
} catch (e) { } catch (e) {
log('err_take_video', e); log(e);
} }
} }
@ -531,7 +531,7 @@ class MessageBox extends Component {
const image = await ImagePicker.openPicker(this.libraryPickerConfig); const image = await ImagePicker.openPicker(this.libraryPickerConfig);
this.showUploadModal(image); this.showUploadModal(image);
} catch (e) { } catch (e) {
log('err_choose_from_library', e); log(e);
} }
} }
@ -618,7 +618,7 @@ class MessageBox extends Component {
if (e && e.error === 'error-file-too-large') { if (e && e.error === 'error-file-too-large') {
return Alert.alert(I18n.t(e.error)); return Alert.alert(I18n.t(e.error));
} }
log('err_finish_audio_message', e); log(e);
} }
} }
} }

View File

@ -407,5 +407,5 @@ export default {
Version_no: 'Version: {{version}}', Version_no: 'Version: {{version}}',
You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!', You_will_not_be_able_to_recover_this_message: 'You will not be able to recover this message!',
Change_Language: 'Change Language', Change_Language: 'Change Language',
Crash_report_disclaimer: 'We never track the content of your chats. The crash report only contains relevant information for us in order ' Crash_report_disclaimer: 'We never track the content of your chats. The crash report only contains relevant information for us in order to identify problems and fix it.'
}; };

View File

@ -16,7 +16,9 @@ import { initializePushNotifications, onNotification } from './notifications/pus
import store from './lib/createStore'; import store from './lib/createStore';
import NotificationBadge from './notifications/inApp'; import NotificationBadge from './notifications/inApp';
import { defaultHeader, onNavigationStateChange } from './utils/navigation'; import { defaultHeader, onNavigationStateChange } from './utils/navigation';
import { loggerConfig, analytics } from './utils/log';
import Toast from './containers/Toast'; import Toast from './containers/Toast';
import RocketChat from './lib/rocketchat';
useScreens(); useScreens();
@ -256,6 +258,7 @@ export default class Root extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.init(); this.init();
this.initCrashReport();
} }
componentDidMount() { componentDidMount() {
@ -285,6 +288,17 @@ export default class Root extends React.Component {
} }
} }
initCrashReport = () => {
RocketChat.getAllowCrashReport()
.then((allowCrashReport) => {
if (!allowCrashReport) {
loggerConfig.autoNotify = false;
loggerConfig.registerBeforeSendCallback(() => false);
analytics().setAnalyticsCollectionEnabled(false);
}
});
}
render() { render() {
return ( return (
<Provider store={store}> <Provider store={store}>

View File

@ -68,7 +68,7 @@ export default function() {
database.delete(emojiRecord); database.delete(emojiRecord);
} }
} catch (e) { } catch (e) {
log('err_get_emojis_delete', e); log(e);
} }
}); });
} }
@ -77,7 +77,7 @@ export default function() {
); );
} }
} catch (e) { } catch (e) {
log('err_get_custom_emojis', e); log(e);
return resolve(); return resolve();
} }
}); });

View File

@ -16,7 +16,7 @@ const create = (permissions) => {
try { try {
database.create('permissions', permission, true); database.create('permissions', permission, true);
} catch (e) { } catch (e) {
log('err_get_permissions_create', e); log(e);
} }
}); });
} }
@ -65,7 +65,7 @@ export default function() {
database.delete(permission); database.delete(permission);
} }
} catch (e) { } catch (e) {
log('err_get_permissions_delete', e); log(e);
} }
}); });
} }
@ -74,7 +74,7 @@ export default function() {
); );
} }
} catch (e) { } catch (e) {
log('err_get_permissions', e); log(e);
return resolve(); return resolve();
} }
}); });

View File

@ -21,14 +21,14 @@ export default function() {
try { try {
database.create('roles', role, true); database.create('roles', role, true);
} catch (e) { } catch (e) {
log('err_get_roles_create', e); log(e);
} }
})); }));
return resolve(); return resolve();
}); });
} }
} catch (e) { } catch (e) {
log('err_get_roles', e); log(e);
return resolve(); return resolve();
} }
}); });

View File

@ -11,7 +11,7 @@ function updateServer(param) {
try { try {
database.databases.serversDB.create('servers', { id: reduxStore.getState().server.server, ...param }, true); database.databases.serversDB.create('servers', { id: reduxStore.getState().server.server, ...param }, true);
} catch (e) { } catch (e) {
log('err_get_settings_update_server', e); log(e);
} }
}); });
} }
@ -34,7 +34,7 @@ export default async function() {
try { try {
database.create('settings', { ...setting, _updatedAt: new Date() }, true); database.create('settings', { ...setting, _updatedAt: new Date() }, true);
} catch (e) { } catch (e) {
log('err_get_settings_create', e); log(e);
} }
if (setting._id === 'Site_Name') { if (setting._id === 'Site_Name') {
@ -61,6 +61,6 @@ export default async function() {
updateServer.call(this, { iconURL }); updateServer.call(this, { iconURL });
} }
} catch (e) { } catch (e) {
log('err_get_settings', e); log(e);
} }
} }

View File

@ -29,7 +29,7 @@ export default function() {
}); });
} }
} catch (e) { } catch (e) {
log('err_get_slash_command', e); log(e);
return resolve(); return resolve();
} }
}); });

View File

@ -13,8 +13,8 @@ async function load({ rid: roomId, latest, t }) {
return []; return [];
} }
return data.messages; return data.messages;
} catch (error) { } catch (e) {
console.log(error); log(e);
return []; return [];
} }
} }
@ -52,7 +52,7 @@ export default function loadMessagesForRoom(...args) {
database.create('threadMessages', message, true); database.create('threadMessages', message, true);
} }
} catch (e) { } catch (e) {
log('err_load_messages_for_room_create', e); log(e);
} }
})); }));
return resolve(data); return resolve(data);
@ -61,7 +61,7 @@ export default function loadMessagesForRoom(...args) {
return resolve([]); return resolve([]);
} }
} catch (e) { } catch (e) {
log('err_load_messages_for_room', e); log(e);
reject(e); reject(e);
} }
}); });

View File

@ -45,7 +45,7 @@ export default function loadMissedMessages(...args) {
database.create('threadMessages', message, true); database.create('threadMessages', message, true);
} }
} catch (e) { } catch (e) {
log('err_load_missed_messages_create', e); log(e);
} }
})); }));
}); });
@ -65,14 +65,14 @@ export default function loadMissedMessages(...args) {
}); });
}); });
} catch (e) { } catch (e) {
log('err_load_missed_messages_delete', e); log(e);
} }
}); });
} }
} }
resolve(); resolve();
} catch (e) { } catch (e) {
log('err_load_missed_messages', e); log(e);
reject(e); reject(e);
} }
}); });

View File

@ -34,7 +34,7 @@ export default function loadThreadMessages({ tmid, offset = 0 }) {
message.rid = tmid; message.rid = tmid;
database.create('threadMessages', message, true); database.create('threadMessages', message, true);
} catch (e) { } catch (e) {
log('err_load_thread_messages_create', e); log(e);
} }
})); }));
return resolve(data); return resolve(data);
@ -43,7 +43,7 @@ export default function loadThreadMessages({ tmid, offset = 0 }) {
return resolve([]); return resolve([]);
} }
} catch (e) { } catch (e) {
log('err_load_thread_messages', e); log(e);
reject(e); reject(e);
} }
}); });

View File

@ -18,6 +18,6 @@ export default async function readMessages(rid) {
}); });
return data; return data;
} catch (e) { } catch (e) {
log('err_read_messages', e); log(e);
} }
} }

View File

@ -15,7 +15,7 @@ export function cancelUpload(path) {
try { try {
database.delete(upload); database.delete(upload);
} catch (e) { } catch (e) {
log('err_send_file_message_delete_upload', e); log(e);
} }
}); });
delete uploadQueue[path]; delete uploadQueue[path];
@ -45,7 +45,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
try { try {
database.create('uploads', fileInfo, true); database.create('uploads', fileInfo, true);
} catch (e) { } catch (e) {
return log('err_send_file_message_create_upload_1', e); return log(e);
} }
}); });
@ -75,7 +75,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
try { try {
database.create('uploads', fileInfo, true); database.create('uploads', fileInfo, true);
} catch (e) { } catch (e) {
return log('err_send_file_message_create_upload_2', e); return log(e);
} }
}); });
}; };
@ -90,7 +90,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
resolve(response); resolve(response);
} catch (e) { } catch (e) {
reject(e); reject(e);
log('err_send_file_message_delete_upload', e); log(e);
} }
}); });
} else { } else {
@ -102,7 +102,7 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
reject(response); reject(response);
} catch (err) { } catch (err) {
reject(err); reject(err);
log('err_send_file_message_create_upload_3', err); log(err);
} }
}); });
} }
@ -116,14 +116,14 @@ export function sendFileMessage(rid, fileInfo, tmid, server, user) {
reject(e); reject(e);
} catch (err) { } catch (err) {
reject(err); reject(err);
log('err_send_file_message_create_upload_3', err); log(err);
} }
}); });
}; };
xhr.send(formData); xhr.send(formData);
} catch (err) { } catch (err) {
log('err_send_file_message_create_upload_4', err); log(err);
} }
}); });
} }

View File

@ -66,6 +66,6 @@ export default async function(rid, msg, tmid, user) {
}); });
} }
} catch (e) { } catch (e) {
log('err_send_message', e); log(e);
} }
} }

View File

@ -38,8 +38,8 @@ export default function subscribeRoom({ rid }) {
clearTimeout(typingTimeouts[username]); clearTimeout(typingTimeouts[username]);
typingTimeouts[username] = null; typingTimeouts[username] = null;
} }
} catch (error) { } catch (e) {
log('err_remove_user_typing', error); log(e);
} }
}; };
@ -60,8 +60,8 @@ export default function subscribeRoom({ rid }) {
typingTimeouts[username] = setTimeout(() => { typingTimeouts[username] = setTimeout(() => {
removeUserTyping(username); removeUserTyping(username);
}, 10000); }, 10000);
} catch (error) { } catch (e) {
log('err_add_user_typing', error); log(e);
} }
} }
}; };
@ -172,7 +172,7 @@ export default function subscribeRoom({ rid }) {
try { try {
promises = this.sdk.subscribeRoom(rid); promises = this.sdk.subscribeRoom(rid);
} catch (e) { } catch (e) {
log('err_subscribe_room', e); log(e);
} }
return { return {

View File

@ -44,7 +44,7 @@ export default function subscribeRooms() {
database.delete(subscription); database.delete(subscription);
}); });
} catch (e) { } catch (e) {
log('err_stream_msg_received_sub_removed', e); log(e);
} }
} else { } else {
const rooms = database.objects('rooms').filtered('_id == $0', data.rid); const rooms = database.objects('rooms').filtered('_id == $0', data.rid);
@ -55,7 +55,7 @@ export default function subscribeRooms() {
database.delete(rooms); database.delete(rooms);
}); });
} catch (e) { } catch (e) {
log('err_stream_msg_received_sub_updated', e); log(e);
} }
} }
} }
@ -68,7 +68,7 @@ export default function subscribeRooms() {
database.create('subscriptions', tmp, true); database.create('subscriptions', tmp, true);
}); });
} catch (e) { } catch (e) {
log('err_stream_msg_received_room_updated', e); log(e);
} }
} else if (type === 'inserted') { } else if (type === 'inserted') {
try { try {
@ -76,7 +76,7 @@ export default function subscribeRooms() {
database.create('rooms', data, true); database.create('rooms', data, true);
}); });
} catch (e) { } catch (e) {
log('err_stream_msg_received_room_inserted', e); log(e);
} }
} }
} }
@ -101,7 +101,7 @@ export default function subscribeRooms() {
database.create('messages', message, true); database.create('messages', message, true);
}); });
} catch (e) { } catch (e) {
log('err_stream_msg_received_message', e); log(e);
} }
}); });
} }
@ -139,7 +139,7 @@ export default function subscribeRooms() {
stop: () => stop() stop: () => stop()
}; };
} catch (e) { } catch (e) {
log('err_subscribe_rooms', e); log(e);
return Promise.reject(); return Promise.reject();
} }
} }

View File

@ -45,6 +45,7 @@ import { SERVERS, SERVER_URL } from '../constants/userDefaults';
const TOKEN_KEY = 'reactnativemeteor_usertoken'; const TOKEN_KEY = 'reactnativemeteor_usertoken';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY'; const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
export const MARKDOWN_KEY = 'RC_MARKDOWN_KEY'; export const MARKDOWN_KEY = 'RC_MARKDOWN_KEY';
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
const returnAnArray = obj => obj || []; const returnAnArray = obj => obj || [];
const MIN_ROCKETCHAT_VERSION = '0.70.0'; const MIN_ROCKETCHAT_VERSION = '0.70.0';
@ -85,7 +86,7 @@ const RocketChat = {
return result; return result;
} }
} catch (e) { } catch (e) {
log('err_get_server_info', e); log(e);
} }
return { return {
success: false, success: false,
@ -433,7 +434,7 @@ const RocketChat = {
database.create('messages', message, true); database.create('messages', message, true);
}); });
} catch (e) { } catch (e) {
log('err_resend_message', e); log(e);
} }
} }
}, },
@ -564,7 +565,7 @@ const RocketChat = {
try { try {
room = await RocketChat.getRoom(message.rid); room = await RocketChat.getRoom(message.rid);
} catch (e) { } catch (e) {
log('err_get_permalink', e); log(e);
return null; return null;
} }
const { server } = reduxStore.getState().server; const { server } = reduxStore.getState().server;
@ -765,6 +766,13 @@ const RocketChat = {
} }
return JSON.parse(useMarkdown); return JSON.parse(useMarkdown);
}, },
async getAllowCrashReport() {
const allowCrashReport = await AsyncStorage.getItem(CRASH_REPORT_KEY);
if (allowCrashReport === null) {
return true;
}
return JSON.parse(allowCrashReport);
},
async getSortPreferences() { async getSortPreferences() {
const prefs = await RNUserDefaults.objectForKey(SORT_PREFS_KEY); const prefs = await RNUserDefaults.objectForKey(SORT_PREFS_KEY);
return prefs; return prefs;
@ -963,8 +971,8 @@ const RocketChat = {
const autoTranslatePermission = database.objectForPrimaryKey('permissions', 'auto-translate'); const autoTranslatePermission = database.objectForPrimaryKey('permissions', 'auto-translate');
const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || []; const userRoles = (reduxStore.getState().login.user && reduxStore.getState().login.user.roles) || [];
return autoTranslatePermission.roles.some(role => userRoles.includes(role)); return autoTranslatePermission.roles.some(role => userRoles.includes(role));
} catch (error) { } catch (e) {
log('err_can_auto_translate', error); log(e);
return false; return false;
} }
}, },

View File

@ -0,0 +1,17 @@
import { TOGGLE_CRASH_REPORT } from '../actions/actionsTypes';
const initialState = {
allowCrashReport: false
};
export default (state = initialState, action) => {
switch (action.type) {
case TOGGLE_CRASH_REPORT:
return {
allowCrashReport: action.payload
};
default:
return state;
}
};

View File

@ -12,6 +12,7 @@ import sortPreferences from './sortPreferences';
import notification from './notification'; import notification from './notification';
import markdown from './markdown'; import markdown from './markdown';
import share from './share'; import share from './share';
import crashReport from './crashReport';
export default combineReducers({ export default combineReducers({
settings, settings,
@ -26,5 +27,6 @@ export default combineReducers({
sortPreferences, sortPreferences,
notification, notification,
markdown, markdown,
share share,
crashReport
}); });

View File

@ -7,6 +7,7 @@ import * as actions from '../actions';
import { selectServerRequest } from '../actions/server'; import { selectServerRequest } from '../actions/server';
import { setAllPreferences } from '../actions/sortPreferences'; import { setAllPreferences } from '../actions/sortPreferences';
import { toggleMarkdown } from '../actions/markdown'; import { toggleMarkdown } from '../actions/markdown';
import { toggleCrashReport } from '../actions/crashReport';
import { APP } from '../actions/actionsTypes'; import { APP } from '../actions/actionsTypes';
import RocketChat from '../lib/rocketchat'; import RocketChat from '../lib/rocketchat';
import log from '../utils/log'; import log from '../utils/log';
@ -46,7 +47,7 @@ const restore = function* restore() {
serversDB.create('servers', serverInfo, true); serversDB.create('servers', serverInfo, true);
await RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ serverInfo.id }`, serverItem[USER_ID]); await RNUserDefaults.set(`${ RocketChat.TOKEN_KEY }-${ serverInfo.id }`, serverItem[USER_ID]);
} catch (e) { } catch (e) {
log('err_create_servers', e); log(e);
} }
}); });
}); });
@ -66,6 +67,9 @@ const restore = function* restore() {
const useMarkdown = yield RocketChat.getUseMarkdown(); const useMarkdown = yield RocketChat.getUseMarkdown();
yield put(toggleMarkdown(useMarkdown)); yield put(toggleMarkdown(useMarkdown));
const allowCrashReport = yield RocketChat.getAllowCrashReport();
yield put(toggleCrashReport(allowCrashReport));
if (!token || !server) { if (!token || !server) {
yield all([ yield all([
RNUserDefaults.clear(RocketChat.TOKEN_KEY), RNUserDefaults.clear(RocketChat.TOKEN_KEY),
@ -79,7 +83,7 @@ const restore = function* restore() {
yield put(actions.appReady({})); yield put(actions.appReady({}));
} catch (e) { } catch (e) {
log('err_restore', e); log(e);
} }
}; };

View File

@ -82,7 +82,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
try { try {
serversDB.create('user', user, true); serversDB.create('user', user, true);
} catch (e) { } catch (e) {
log('err_set_user_token', e); log(e);
} }
}); });
@ -99,7 +99,7 @@ const handleLoginSuccess = function* handleLoginSuccess({ user }) {
yield put(appStart('inside')); yield put(appStart('inside'));
} }
} catch (e) { } catch (e) {
log('err_handle_login_success', e); log(e);
} }
}; };
@ -128,7 +128,7 @@ const handleLogout = function* handleLogout() {
yield put(appStart('outside')); yield put(appStart('outside'));
} catch (e) { } catch (e) {
yield put(appStart('outside')); yield put(appStart('outside'));
log('err_handle_logout', e); log(e);
} }
} }
}; };

View File

@ -78,7 +78,7 @@ const handleReplyBroadcast = function* handleReplyBroadcast({ message }) {
yield delay(500); yield delay(500);
yield put(replyInit(message, false)); yield put(replyInit(message, false));
} catch (e) { } catch (e) {
log('err_reply_broadcast', e); log(e);
} }
}; };

View File

@ -23,7 +23,7 @@ const watchUserTyping = function* watchUserTyping({ rid, status }) {
yield RocketChat.emitTyping(rid, false); yield RocketChat.emitTyping(rid, false);
} }
} catch (e) { } catch (e) {
log('err_watch_user_typing', e); log(e);
} }
}; };

View File

@ -33,8 +33,8 @@ const handleRoomsRequest = function* handleRoomsRequest() {
subscriptions.forEach((subscription) => { subscriptions.forEach((subscription) => {
try { try {
database.create('subscriptions', subscription, true); database.create('subscriptions', subscription, true);
} catch (error) { } catch (e) {
log('err_rooms_request_create_sub', error); log(e);
} }
}); });
}); });
@ -42,14 +42,14 @@ const handleRoomsRequest = function* handleRoomsRequest() {
try { try {
database.databases.serversDB.create('servers', { id: server, roomsUpdatedAt: newRoomsUpdatedAt }, true); database.databases.serversDB.create('servers', { id: server, roomsUpdatedAt: newRoomsUpdatedAt }, true);
} catch (e) { } catch (e) {
log('err_rooms_request_update', e); log(e);
} }
}); });
yield put(roomsSuccess()); yield put(roomsSuccess());
} catch (e) { } catch (e) {
yield put(roomsFailure(e)); yield put(roomsFailure(e));
log('err_rooms_request', e); log(e);
} }
}; };

View File

@ -34,7 +34,7 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {
return serverInfo; return serverInfo;
} catch (e) { } catch (e) {
log('err_get_server_info', e); log(e);
} }
}; };
@ -73,7 +73,7 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
yield put(selectServerSuccess(server, (serverInfo && serverInfo.version) || version)); yield put(selectServerSuccess(server, (serverInfo && serverInfo.version) || version));
} catch (e) { } catch (e) {
yield put(selectServerFailure()); yield put(selectServerFailure());
log('err_select_server', e); log(e);
} }
}; };
@ -91,7 +91,7 @@ const handleServerRequest = function* handleServerRequest({ server }) {
yield put(selectServerRequest(server, serverInfo.version, false)); yield put(selectServerRequest(server, serverInfo.version, false));
} catch (e) { } catch (e) {
yield put(serverFailure()); yield put(serverFailure());
log('err_server_request', e); log(e);
} }
}; };

View File

@ -18,7 +18,7 @@ const appHasComeBackToForeground = function* appHasComeBackToForeground() {
setBadgeCount(); setBadgeCount();
return yield RocketChat.setUserPresenceOnline(); return yield RocketChat.setUserPresenceOnline();
} catch (e) { } catch (e) {
log('err_app_has_come_back_to_foreground', e); log(e);
} }
}; };
@ -34,7 +34,7 @@ const appHasComeBackToBackground = function* appHasComeBackToBackground() {
try { try {
return yield RocketChat.setUserPresenceAway(); return yield RocketChat.setUserPresenceAway();
} catch (e) { } catch (e) {
log('err_app_has_come_back_to_background', e); log(e);
} }
}; };

View File

@ -31,7 +31,7 @@ class EventEmitter {
try { try {
listener.apply(this, args); listener.apply(this, args);
} catch (e) { } catch (e) {
log('err_emit', e); log(e);
} }
}); });
} }

View File

@ -1,11 +1,11 @@
import { Client } from 'bugsnag-react-native';
import firebase from 'react-native-firebase'; import firebase from 'react-native-firebase';
import config from '../../config';
export default (event, error) => { const bugsnag = new Client(config.BUGSNAG_API_KEY);
if (typeof error !== 'object') {
error = { error }; export const { analytics } = firebase;
} export const loggerConfig = bugsnag.config;
firebase.analytics().logEvent(event); export const { leaveBreadcrumb } = bugsnag;
if (__DEV__) {
console.warn(event, error); export default bugsnag.notify;
}
};

View File

@ -1,4 +1,4 @@
import firebase from 'react-native-firebase'; import { analytics, leaveBreadcrumb } from './log';
import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from '../constants/colors'; import { HEADER_BACKGROUND, HEADER_TITLE, HEADER_BACK } from '../constants/colors';
@ -31,6 +31,7 @@ export const onNavigationStateChange = (prevState, currentState) => {
const prevScreen = getActiveRouteName(prevState); const prevScreen = getActiveRouteName(prevState);
if (prevScreen !== currentScreen) { if (prevScreen !== currentScreen) {
firebase.analytics().setCurrentScreen(currentScreen); analytics().setCurrentScreen(currentScreen);
leaveBreadcrumb(currentScreen, { type: 'navigation' });
} }
}; };

View File

@ -99,8 +99,8 @@ class DirectoryView extends React.Component {
} else { } else {
this.setState({ loading: false }); this.setState({ loading: false });
} }
} catch (error) { } catch (e) {
log('err_load_directory', error); log(e);
this.setState({ loading: false }); this.setState({ loading: false });
} }
}, 200) }, 200)

View File

@ -109,7 +109,7 @@ class LanguageView extends React.Component {
this.setState({ saving: false }); this.setState({ saving: false });
setTimeout(() => { setTimeout(() => {
showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') })); showErrorAlert(I18n.t('There_was_an_error_while_action', { action: I18n.t('saving_preferences') }));
log('err_save_user_preferences', e); log(e);
}, 300); }, 300);
} }
} }

View File

@ -6,7 +6,7 @@ import {
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { SafeAreaView } from 'react-navigation'; import { SafeAreaView } from 'react-navigation';
import equal from 'deep-equal'; import equal from 'deep-equal';
import firebase from 'react-native-firebase'; import { analytics } from '../utils/log';
import KeyboardView from '../presentation/KeyboardView'; import KeyboardView from '../presentation/KeyboardView';
import TextInput from '../containers/TextInput'; import TextInput from '../containers/TextInput';
@ -156,7 +156,7 @@ class LoginView extends React.Component {
const { loginRequest } = this.props; const { loginRequest } = this.props;
Keyboard.dismiss(); Keyboard.dismiss();
loginRequest({ user, password, code }); loginRequest({ user, password, code });
firebase.analytics().logEvent('login'); analytics().logEvent('login');
} }
register = () => { register = () => {

View File

@ -63,7 +63,7 @@ class ProfileView extends React.Component {
const result = await RocketChat.getAvatarSuggestion(); const result = await RocketChat.getAvatarSuggestion();
this.setState({ avatarSuggestions: result }); this.setState({ avatarSuggestions: result });
} catch (e) { } catch (e) {
log('err_get_avatar_suggestion', e); log(e);
} }
} }

View File

@ -47,7 +47,7 @@ class RegisterView extends React.Component {
try { try {
this.parsedCustomFields = JSON.parse(props.Accounts_CustomFields); this.parsedCustomFields = JSON.parse(props.Accounts_CustomFields);
} catch (e) { } catch (e) {
log('err_parsing_account_custom_fields', e); log(e);
} }
} }
Object.keys(this.parsedCustomFields).forEach((key) => { Object.keys(this.parsedCustomFields).forEach((key) => {

View File

@ -64,8 +64,8 @@ class RoomActionsView extends React.Component {
if (result.success) { if (result.success) {
this.setState({ room: { ...result.channel, rid: result.channel._id } }); this.setState({ room: { ...result.channel, rid: result.channel._id } });
} }
} catch (error) { } catch (e) {
log('err_get_channel_info', error); log(e);
} }
} }
@ -75,8 +75,8 @@ class RoomActionsView extends React.Component {
if (counters.success) { if (counters.success) {
this.setState({ membersCount: counters.members, joined: counters.joined }); this.setState({ membersCount: counters.members, joined: counters.joined });
} }
} catch (error) { } catch (e) {
log('err_get_room_counters', error); log(e);
} }
} else if (room.t === 'd') { } else if (room.t === 'd') {
this.updateRoomMember(); this.updateRoomMember();
@ -341,7 +341,7 @@ class RoomActionsView extends React.Component {
this.setState({ member: result.user }); this.setState({ member: result.user });
} }
} catch (e) { } catch (e) {
log('err_update_room_member', e); log(e);
this.setState({ member: {} }); this.setState({ member: {} });
} }
} }
@ -353,7 +353,7 @@ class RoomActionsView extends React.Component {
try { try {
RocketChat.toggleBlockUser(rid, member._id, !blocker); RocketChat.toggleBlockUser(rid, member._id, !blocker);
} catch (e) { } catch (e) {
log('err_toggle_block_user', e); log(e);
} }
} }
@ -394,7 +394,7 @@ class RoomActionsView extends React.Component {
}; };
RocketChat.saveNotificationSettings(room.rid, notifications); RocketChat.saveNotificationSettings(room.rid, notifications);
} catch (e) { } catch (e) {
log('err_toggle_notifications', e); log(e);
} }
} }

View File

@ -206,7 +206,7 @@ class RoomInfoEditView extends React.Component {
this.setState({ nameError: e }); this.setState({ nameError: e });
} }
error = true; error = true;
log('err_save_room_settings', e); log(e);
} }
await this.setState({ saving: false }); await this.setState({ saving: false });
@ -261,7 +261,7 @@ class RoomInfoEditView extends React.Component {
try { try {
await RocketChat.toggleArchiveRoom(rid, t, !archived); await RocketChat.toggleArchiveRoom(rid, t, !archived);
} catch (e) { } catch (e) {
log('err_toggle_archive', e); log(e);
} }
} }
} }

View File

@ -79,8 +79,8 @@ class RoomInfoView extends React.Component {
if (result.success) { if (result.success) {
this.setState({ roomUser: result.user }); this.setState({ roomUser: result.user });
} }
} catch (error) { } catch (e) {
log('err_get_user_info', error); log(e);
} }
return; return;
} }

View File

@ -138,7 +138,7 @@ class RoomMembersView extends React.Component {
} }
} }
} catch (e) { } catch (e) {
log('err_on_press_user', e); log(e);
} }
} }
@ -169,7 +169,7 @@ class RoomMembersView extends React.Component {
this.fetchMembers(); this.fetchMembers();
}); });
} catch (e) { } catch (e) {
log('err_toggle_status', e); log(e);
} }
} }
@ -203,8 +203,8 @@ class RoomMembersView extends React.Component {
end: newMembers.length < PAGE_SIZE end: newMembers.length < PAGE_SIZE
}); });
navigation.setParams({ allUsers }); navigation.setParams({ allUsers });
} catch (error) { } catch (e) {
log('err_fetch_members, error'); log(e);
this.setState({ isLoading: false }); this.setState({ isLoading: false });
} }
} }
@ -228,7 +228,7 @@ class RoomMembersView extends React.Component {
await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted); await RocketChat.toggleMuteUserInRoom(rid, userLongPressed.username, !userLongPressed.muted);
EventEmitter.emit(LISTENER, { message: I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }) }); EventEmitter.emit(LISTENER, { message: I18n.t('User_has_been_key', { key: userLongPressed.muted ? I18n.t('unmuted') : I18n.t('muted') }) });
} catch (e) { } catch (e) {
log('err_handle_mute', e); log(e);
} }
} }

View File

@ -105,7 +105,7 @@ export class List extends React.PureComponent {
this.setState({ end: result.length < 50, loading: false }); this.setState({ end: result.length < 50, loading: false });
} catch (e) { } catch (e) {
this.setState({ loading: false }); this.setState({ loading: false });
log('err_list_view_on_end_reached', e); log(e);
} }
}, 300) }, 300)

View File

@ -116,7 +116,7 @@ class UploadProgress extends Component {
try { try {
database.write(() => database.delete(uploadItem[0])); database.write(() => database.delete(uploadItem[0]));
} catch (e) { } catch (e) {
log('err_upload_progress_delete', e); log(e);
} }
} }
@ -124,7 +124,7 @@ class UploadProgress extends Component {
try { try {
await RocketChat.cancelUpload(item.path); await RocketChat.cancelUpload(item.path);
} catch (e) { } catch (e) {
log('err_upload_progress_cancel', e); log(e);
} }
} }
@ -137,7 +137,7 @@ class UploadProgress extends Component {
}); });
await RocketChat.sendFileMessage(rid, item, undefined, server, user); await RocketChat.sendFileMessage(rid, item, undefined, server, user);
} catch (e) { } catch (e) {
log('err_upload_progress_try_again', e); log(e);
} }
} }

View File

@ -294,7 +294,7 @@ class RoomView extends React.Component {
this.setState({ canAutoTranslate }); this.setState({ canAutoTranslate });
}); });
} catch (e) { } catch (e) {
log('err_room_init', e); log(e);
} }
} }
@ -320,7 +320,7 @@ class RoomView extends React.Component {
} }
RocketChat.setReaction(shortname, messageId); RocketChat.setReaction(shortname, messageId);
} catch (e) { } catch (e) {
log('err_room_on_reaction_press', e); log(e);
} }
}; };
@ -427,7 +427,7 @@ class RoomView extends React.Component {
} }
return Promise.resolve(); return Promise.resolve();
} catch (e) { } catch (e) {
log('err_get_messages', e); log(e);
} }
} }
@ -435,7 +435,7 @@ class RoomView extends React.Component {
try { try {
return RocketChat.loadThreadMessages({ tmid: this.tmid }); return RocketChat.loadThreadMessages({ tmid: this.tmid });
} catch (e) { } catch (e) {
log('err_get_thread_messages', e); log(e);
} }
} }
@ -448,7 +448,7 @@ class RoomView extends React.Component {
joined: true joined: true
}); });
} catch (e) { } catch (e) {
log('err_join_room', e); log(e);
} }
}; };
@ -460,8 +460,8 @@ class RoomView extends React.Component {
database.write(() => { database.write(() => {
database.create('threads', buildMessage(EJSON.fromJSONValue(thread)), true); database.create('threads', buildMessage(EJSON.fromJSONValue(thread)), true);
}); });
} catch (error) { } catch (e) {
log('err_fetch_thread_name', error); log(e);
} }
} }
@ -470,7 +470,7 @@ class RoomView extends React.Component {
await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread); await RocketChat.toggleFollowMessage(this.tmid, !isFollowingThread);
EventEmitter.emit(LISTENER, { message: isFollowingThread ? 'Unfollowed thread' : 'Following thread' }); EventEmitter.emit(LISTENER, { message: isFollowingThread ? 'Unfollowed thread' : 'Following thread' });
} catch (e) { } catch (e) {
log('err_toggle_follow_thread', e); log(e);
} }
} }

View File

@ -58,7 +58,7 @@ class Sort extends PureComponent {
setSortPreference(param); setSortPreference(param);
RocketChat.saveSortPreference(param); RocketChat.saveSortPreference(param);
} catch (e) { } catch (e) {
log('err_set_sort_preference', e); log(e);
} }
} }

View File

@ -350,7 +350,7 @@ class RoomsListView extends React.Component {
return this.goRoom({ rid: result.room._id, name: username, t: 'd' }); return this.goRoom({ rid: result.room._id, name: username, t: 'd' });
} }
} catch (e) { } catch (e) {
log('err_on_press_item', e); log(e);
} }
} else { } else {
return this.goRoom(item); return this.goRoom(item);
@ -383,7 +383,7 @@ class RoomsListView extends React.Component {
}); });
} }
} catch (e) { } catch (e) {
log('error_toggle_favorite', e); log(e);
} }
} }
@ -399,7 +399,7 @@ class RoomsListView extends React.Component {
}); });
} }
} catch (e) { } catch (e) {
log('error_toggle_read', e); log(e);
} }
} }
@ -413,7 +413,7 @@ class RoomsListView extends React.Component {
}); });
} }
} catch (e) { } catch (e) {
log('error_hide_channel', e); log(e);
} }
} }

View File

@ -68,9 +68,9 @@ class SearchMessagesView extends React.Component {
loading: false loading: false
}); });
} }
} catch (error) { } catch (e) {
this.setState({ loading: false }); this.setState({ loading: false });
log('err_search_messages', error); log(e);
} }
}, 1000) }, 1000)

View File

@ -118,7 +118,7 @@ class SelectedUsersView extends React.Component {
await RocketChat.addUsersToRoom(rid); await RocketChat.addUsersToRoom(rid);
navigation.pop(); navigation.pop();
} catch (e) { } catch (e) {
log('err_add_user', e); log(e);
} finally { } finally {
setLoadingInvite(false); setLoadingInvite(false);
} }

View File

@ -83,7 +83,7 @@ class SetUsernameView extends React.Component {
await RocketChat.setUsername(username); await RocketChat.setUsername(username);
await loginRequest({ resume: token }); await loginRequest({ resume: token });
} catch (e) { } catch (e) {
log('err_submit_username', e); log(e);
} }
this.setState({ saving: false }); this.setState({ saving: false });
} }

View File

@ -1,11 +1,12 @@
import React from 'react'; import React from 'react';
import { import {
View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch, Share View, Linking, ScrollView, AsyncStorage, SafeAreaView, Switch, Text, Share
} from 'react-native'; } from 'react-native';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown'; import { toggleMarkdown as toggleMarkdownAction } from '../../actions/markdown';
import { toggleCrashReport as toggleCrashReportAction } from '../../actions/crashReport';
import { SWITCH_TRACK_COLOR } from '../../constants/colors'; import { SWITCH_TRACK_COLOR } from '../../constants/colors';
import { DrawerButton } from '../../containers/HeaderButton'; import { DrawerButton } from '../../containers/HeaderButton';
import StatusBar from '../../containers/StatusBar'; import StatusBar from '../../containers/StatusBar';
@ -13,16 +14,25 @@ import ListItem from '../../containers/ListItem';
import { DisclosureImage } from '../../containers/DisclosureIndicator'; import { DisclosureImage } from '../../containers/DisclosureIndicator';
import Separator from '../../containers/Separator'; import Separator from '../../containers/Separator';
import I18n from '../../i18n'; import I18n from '../../i18n';
import { MARKDOWN_KEY } from '../../lib/rocketchat'; import { MARKDOWN_KEY, CRASH_REPORT_KEY } from '../../lib/rocketchat';
import { getReadableVersion, getDeviceModel, isAndroid } from '../../utils/deviceInfo'; import { getReadableVersion, getDeviceModel, isAndroid } from '../../utils/deviceInfo';
import openLink from '../../utils/openLink'; import openLink from '../../utils/openLink';
import scrollPersistTaps from '../../utils/scrollPersistTaps'; import scrollPersistTaps from '../../utils/scrollPersistTaps';
import { showErrorAlert } from '../../utils/info'; import { showErrorAlert } from '../../utils/info';
import styles from './styles'; import styles from './styles';
import sharedStyles from '../Styles'; import sharedStyles from '../Styles';
import { loggerConfig, analytics } from '../../utils/log';
import { PLAY_MARKET_LINK, APP_STORE_LINK, LICENSE_LINK } from '../../constants/links'; import { PLAY_MARKET_LINK, APP_STORE_LINK, LICENSE_LINK } from '../../constants/links';
const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />); const SectionSeparator = React.memo(() => <View style={styles.sectionSeparatorBorder} />);
const ItemInfo = React.memo(({ info }) => (
<View style={styles.infoContainer}>
<Text style={styles.infoText}>{info}</Text>
</View>
));
ItemInfo.propTypes = {
info: PropTypes.string
};
class SettingsView extends React.Component { class SettingsView extends React.Component {
static navigationOptions = ({ navigation }) => ({ static navigationOptions = ({ navigation }) => ({
@ -34,7 +44,9 @@ class SettingsView extends React.Component {
navigation: PropTypes.object, navigation: PropTypes.object,
server: PropTypes.object, server: PropTypes.object,
useMarkdown: PropTypes.bool, useMarkdown: PropTypes.bool,
toggleMarkdown: PropTypes.func allowCrashReport: PropTypes.bool,
toggleMarkdown: PropTypes.func,
toggleCrashReport: PropTypes.func
} }
toggleMarkdown = (value) => { toggleMarkdown = (value) => {
@ -43,6 +55,20 @@ class SettingsView extends React.Component {
toggleMarkdown(value); toggleMarkdown(value);
} }
toggleCrashReport = (value) => {
AsyncStorage.setItem(CRASH_REPORT_KEY, JSON.stringify(value));
const { toggleCrashReport } = this.props;
toggleCrashReport(value);
loggerConfig.autoNotify = value;
analytics().setAnalyticsCollectionEnabled(value);
if (value) {
loggerConfig.clearBeforeSendCallbacks();
} else {
loggerConfig.registerBeforeSendCallback(() => false);
}
}
navigateToRoom = (room) => { navigateToRoom = (room) => {
const { navigation } = this.props; const { navigation } = this.props;
navigation.navigate(room); navigation.navigate(room);
@ -81,6 +107,17 @@ class SettingsView extends React.Component {
); );
} }
renderCrashReportSwitch = () => {
const { allowCrashReport } = this.props;
return (
<Switch
value={allowCrashReport}
trackColor={SWITCH_TRACK_COLOR}
onValueChange={this.toggleCrashReport}
/>
);
}
render() { render() {
const { server } = this.props; const { server } = this.props;
return ( return (
@ -88,7 +125,7 @@ class SettingsView extends React.Component {
<StatusBar /> <StatusBar />
<ScrollView <ScrollView
{...scrollPersistTaps} {...scrollPersistTaps}
contentContainerStyle={sharedStyles.listContentContainer} contentContainerStyle={[sharedStyles.listContentContainer, styles.listWithoutBorderBottom]}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
testID='settings-view-list' testID='settings-view-list'
> >
@ -108,13 +145,6 @@ class SettingsView extends React.Component {
right={this.renderDisclosure} right={this.renderDisclosure}
/> />
<Separator /> <Separator />
<ListItem
title={I18n.t('Share_this_app')}
onPress={this.shareApp}
showActionIndicator
testID='settings-view-share-app'
/>
<Separator />
<ListItem <ListItem
title={I18n.t('Theme')} title={I18n.t('Theme')}
showActionIndicator showActionIndicator
@ -122,6 +152,13 @@ class SettingsView extends React.Component {
testID='settings-view-theme' testID='settings-view-theme'
/> />
<Separator /> <Separator />
<ListItem
title={I18n.t('Share_this_app')}
showActionIndicator
disabled
testID='settings-view-share-app'
/>
<Separator />
<SectionSeparator /> <SectionSeparator />
@ -148,6 +185,18 @@ class SettingsView extends React.Component {
testID='settings-view-markdown' testID='settings-view-markdown'
right={() => this.renderMarkdownSwitch()} right={() => this.renderMarkdownSwitch()}
/> />
<SectionSeparator />
<ListItem
title={I18n.t('Send_crash_report')}
testID='settings-view-crash-report'
right={() => this.renderCrashReportSwitch()}
/>
<Separator />
<ItemInfo
info={I18n.t('Crash_report_disclaimer')}
/>
</ScrollView> </ScrollView>
</SafeAreaView> </SafeAreaView>
); );
@ -156,11 +205,13 @@ class SettingsView extends React.Component {
const mapStateToProps = state => ({ const mapStateToProps = state => ({
server: state.server, server: state.server,
useMarkdown: state.markdown.useMarkdown useMarkdown: state.markdown.useMarkdown,
allowCrashReport: state.crashReport.allowCrashReport
}); });
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
toggleMarkdown: params => dispatch(toggleMarkdownAction(params)) toggleMarkdown: params => dispatch(toggleMarkdownAction(params)),
toggleCrashReport: params => dispatch(toggleCrashReportAction(params))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(SettingsView); export default connect(mapStateToProps, mapDispatchToProps)(SettingsView);

View File

@ -8,5 +8,18 @@ export default StyleSheet.create({
...sharedStyles.separatorVertical, ...sharedStyles.separatorVertical,
backgroundColor: COLOR_BACKGROUND_CONTAINER, backgroundColor: COLOR_BACKGROUND_CONTAINER,
height: 10 height: 10
},
listWithoutBorderBottom: {
borderBottomWidth: 0
},
infoContainer: {
padding: 15,
paddingBottom: 40,
backgroundColor: COLOR_BACKGROUND_CONTAINER
},
infoText: {
fontSize: 14,
...sharedStyles.textColorNormal,
...sharedStyles.textRegular
} }
}); });

View File

@ -132,7 +132,7 @@ class ShareListView extends React.Component {
value, fileInfo, isMedia, mediaLoading: false value, fileInfo, isMedia, mediaLoading: false
}); });
} catch (e) { } catch (e) {
log('err_process_media_share_extension', e); log(e);
this.setState({ mediaLoading: false }); this.setState({ mediaLoading: false });
} }

View File

@ -116,7 +116,7 @@ class ShareView extends React.Component {
try { try {
await RocketChat.sendFileMessage(rid, fileMessage, undefined, server, user); await RocketChat.sendFileMessage(rid, fileMessage, undefined, server, user);
} catch (e) { } catch (e) {
log('err_send_media_message', e); log(e);
} }
} }
} }
@ -127,8 +127,8 @@ class ShareView extends React.Component {
if (value !== '' && rid !== '') { if (value !== '' && rid !== '') {
try { try {
await RocketChat.sendMessage(rid, value, undefined, user); await RocketChat.sendMessage(rid, value, undefined, user);
} catch (error) { } catch (e) {
log('err_share_extension_send_message', error); log(e);
} }
} }
}; };

View File

@ -157,7 +157,7 @@ class Sidebar extends Component {
try { try {
RocketChat.setUserPresenceDefaultStatus(item.id); RocketChat.setUserPresenceDefaultStatus(item.id);
} catch (e) { } catch (e) {
log('err_set_user_presence_default_status', e); log(e);
} }
} }
}} }}

View File

@ -112,7 +112,7 @@ class ThreadMessagesView extends React.Component {
try { try {
database.create('threads', buildMessage(message), true); database.create('threads', buildMessage(message), true);
} catch (e) { } catch (e) {
log('err_thread_messages_create', e); log(e);
} }
})); }));
@ -122,8 +122,8 @@ class ThreadMessagesView extends React.Component {
}); });
}); });
} }
} catch (error) { } catch (e) {
log('err_thread_messages_load', error); log(e);
this.setState({ loading: false, end: true }); this.setState({ loading: false, end: true });
} }
}, 300) }, 300)
@ -145,7 +145,7 @@ class ThreadMessagesView extends React.Component {
try { try {
database.create('threads', buildMessage(message), true); database.create('threads', buildMessage(message), true);
} catch (e) { } catch (e) {
log('err_thread_messages_update', e); log(e);
} }
}); });
} }
@ -157,7 +157,7 @@ class ThreadMessagesView extends React.Component {
try { try {
database.delete(oldMessage); database.delete(oldMessage);
} catch (e) { } catch (e) {
log('err_thread_messages_delete', e); log(e);
} }
} }
}); });
@ -169,8 +169,8 @@ class ThreadMessagesView extends React.Component {
}); });
}); });
} }
} catch (error) { } catch (e) {
log('err_thread_messages_sync', error); log(e);
this.setState({ loading: false }); this.setState({ loading: false });
} }
} }

3
config.js Normal file
View File

@ -0,0 +1,3 @@
export default {
BUGSNAG_API_KEY: ''
};

View File

@ -1,2 +1,5 @@
source "https://rubygems.org" source "https://rubygems.org"
gem 'fastlane' gem 'fastlane'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

View File

@ -30,6 +30,7 @@ target 'RocketChatRN' do
use_native_modules! use_native_modules!
use_unimodules! use_unimodules!
end end
target 'ShareRocketChatRN' do target 'ShareRocketChatRN' do

View File

@ -1,5 +1,10 @@
PODS: PODS:
- boost-for-react-native (1.63.0) - boost-for-react-native (1.63.0)
- BugsnagReactNative (2.22.4):
- BugsnagReactNative/Core (= 2.22.4)
- React
- BugsnagReactNative/Core (2.22.4):
- React
- Crashlytics (3.13.4): - Crashlytics (3.13.4):
- Fabric (~> 1.10.2) - Fabric (~> 1.10.2)
- DoubleConversion (1.1.6) - DoubleConversion (1.1.6)
@ -155,7 +160,7 @@ PODS:
- React - React
- react-native-keyboard-tracking-view (5.5.0): - react-native-keyboard-tracking-view (5.5.0):
- React - React
- react-native-notifications (2.0.3): - react-native-notifications (2.0.6):
- React - React
- react-native-orientation-locker (1.1.6): - react-native-orientation-locker (1.1.6):
- React - React
@ -255,6 +260,7 @@ PODS:
- yoga (0.60.4.React) - yoga (0.60.4.React)
DEPENDENCIES: DEPENDENCIES:
- BugsnagReactNative (from `../node_modules/bugsnag-react-native`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`) - EXAppLoaderProvider (from `../node_modules/expo-app-loader-provider/ios`)
- EXConstants (from `../node_modules/expo-constants/ios`) - EXConstants (from `../node_modules/expo-constants/ios`)
@ -336,6 +342,8 @@ SPEC REPOS:
- SDWebImageWebPCoder - SDWebImageWebPCoder
EXTERNAL SOURCES: EXTERNAL SOURCES:
BugsnagReactNative:
:path: "../node_modules/bugsnag-react-native"
DoubleConversion: DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
EXAppLoaderProvider: EXAppLoaderProvider:
@ -479,6 +487,7 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BugsnagReactNative: 2114356c3acac0a71fb4b8962d3d1afdeb35f4d9
Crashlytics: 2dfd686bcb918dc10ee0e76f7f853fe42c7bd552 Crashlytics: 2dfd686bcb918dc10ee0e76f7f853fe42c7bd552
DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2 DoubleConversion: 5805e889d232975c086db112ece9ed034df7a0b2
EXAppLoaderProvider: 7a8185228d8ba9e689a0e2d6d957fe9bdd49c8a0 EXAppLoaderProvider: 7a8185228d8ba9e689a0e2d6d957fe9bdd49c8a0
@ -510,7 +519,7 @@ SPEC CHECKSUMS:
react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061 react-native-document-picker: c36bf5f067a581657ecaf7124dcd921a8be19061
react-native-keyboard-input: 2a01e0aceac330592bbe9b3101761bb9d8e6d1fb react-native-keyboard-input: 2a01e0aceac330592bbe9b3101761bb9d8e6d1fb
react-native-keyboard-tracking-view: 1ebd24a2b6ca2314549aa51775995678094bffa1 react-native-keyboard-tracking-view: 1ebd24a2b6ca2314549aa51775995678094bffa1
react-native-notifications: 3385ff44e246c62e0eabe7ee414fc5e2e6a61fec react-native-notifications: 163ddedac6fcc8d850ea15b06abdadcacdff00f1
react-native-orientation-locker: 23918c400376a7043e752c639c122fcf6bce8f1c react-native-orientation-locker: 23918c400376a7043e752c639c122fcf6bce8f1c
react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091 react-native-realm-path: 868473ea0bc4629850f1ec51a70d81055c06d091
react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865
@ -555,6 +564,6 @@ SPEC CHECKSUMS:
UMTaskManagerInterface: 8664abd37a00715727e60df9ecd65e42ba47b548 UMTaskManagerInterface: 8664abd37a00715727e60df9ecd65e42ba47b548
yoga: c2c050f6ae6e222534760cc82f559b89214b67e2 yoga: c2c050f6ae6e222534760cc82f559b89214b67e2
PODFILE CHECKSUM: c9c0e4d6e34886493451eb2fdba48bc7e89d4551 PODFILE CHECKSUM: 44d04dbfbc6cf6468fe34667ef014d00328c95ff
COCOAPODS: 1.6.2 COCOAPODS: 1.6.2

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/BSGConnectivity.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/BSGOutOfMemoryWatchdog.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/BSGSerialization.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSArchSpecific.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSBacktrace_Private.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrash.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashAdvanced.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashC.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSCrashCallCompletion.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashContext.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashDoctor.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReport.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportFields.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilter.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Reporting/Filters/BSG_KSCrashReportFilterCompletion.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportStore.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashReportVersion.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/BSG_KSCrashReportWriter.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_CPPException.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_MachException.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_NSException.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Private.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_Signal.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Sentry/BSG_KSCrashSentry_User.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashState.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/BSG_KSCrashType.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSDynamicLinker.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSFileUtils.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodec.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSJSONCodecObjC.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSLogger.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMach.h

View File

@ -0,0 +1 @@
../../../../../node_modules/bugsnag-react-native/cocoa/vendor/bugsnag-cocoa/Source/KSCrash/Source/KSCrash/Recording/Tools/BSG_KSMachApple.h

Some files were not shown because too many files have changed in this diff Show More