diff --git a/package.json b/package.json index caf787f8..df67c3a9 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "native": "220508", "major": 4, "minor": 0, - "patch": 1, + "patch": 2, "expo": "45.0.0" }, "description": "tooot app for Mastodon", diff --git a/src/App.tsx b/src/App.tsx index c0032d71..bdf6569a 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -54,6 +54,7 @@ import { enableFreeze } from 'react-native-screens' import { QueryClientProvider } from 'react-query' import { Provider } from 'react-redux' import { PersistGate } from 'redux-persist/integration/react' +import * as Sentry from 'sentry-expo' Platform.select({ android: LogBox.ignoreLogs(['Setting a timer for a long period of time']) @@ -128,13 +129,15 @@ const App: React.FC = () => { } return ( - - - - - - - + + + + + + + + + ) } else { return null diff --git a/src/Screens.tsx b/src/Screens.tsx index 53d27938..805129ff 100644 --- a/src/Screens.tsx +++ b/src/Screens.tsx @@ -322,7 +322,11 @@ const Screens: React.FC = ({ localCorrupt }) => { return ( - + ({ }) }) .catch(error => { - // if (sentry && Math.random() < 0.01) { - // Sentry.Native.setExtras({ - // API: 'general', - // ...(error.response && { response: error.response }), - // ...(error.request && { request: error.request }) - // }) - // Sentry.Native.captureException(error) - // } - - if (error.response) { + if (error?.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error( @@ -80,7 +71,7 @@ const apiGeneral = async ({ status: error.response.status, message: error.response.data.error }) - } else if (error.request) { + } else if (error?.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js @@ -94,7 +85,7 @@ const apiGeneral = async ({ console.error( ctx.bold(' API general '), ctx.bold('internal'), - error.message, + error?.message, url ) return Promise.reject() diff --git a/src/api/instance.ts b/src/api/instance.ts index 73975956..86d9a367 100644 --- a/src/api/instance.ts +++ b/src/api/instance.ts @@ -100,16 +100,7 @@ const apiInstance = async ({ }) }) .catch(error => { - // if (Math.random() < 0.001) { - // Sentry.Native.setExtras({ - // API: 'instance', - // ...(error.response && { response: error.response }), - // ...(error.request && { request: error.request }) - // }) - // Sentry.Native.captureException(error) - // } - - if (error.response) { + if (error?.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error( @@ -122,7 +113,7 @@ const apiInstance = async ({ status: error.response.status, message: error.response.data.error }) - } else if (error.request) { + } else if (error?.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js @@ -132,7 +123,7 @@ const apiInstance = async ({ console.error( ctx.bold(' API instance '), ctx.bold('internal'), - error.message, + error?.message, url ) return Promise.reject() diff --git a/src/api/tooot.ts b/src/api/tooot.ts index 6e7b9ba3..db5c86af 100644 --- a/src/api/tooot.ts +++ b/src/api/tooot.ts @@ -66,16 +66,16 @@ const apiTooot = async ({ }) }) .catch(error => { - if (sentry && Math.random() < 0.01) { + if (sentry && Math.random() < 0.1) { Sentry.Native.setExtras({ API: 'tooot', - ...(error.response && { response: error.response }), - ...(error.request && { request: error.request }) + ...(error?.response && { response: error.response }), + ...(error?.request && { request: error.request }) }) Sentry.Native.captureException(error) } - if (error.response) { + if (error?.response) { // The request was made and the server responded with a status code // that falls out of the range of 2xx console.error( @@ -88,7 +88,7 @@ const apiTooot = async ({ status: error.response.status, message: error.response.data.error }) - } else if (error.request) { + } else if (error?.request) { // The request was made but no response was received // `error.request` is an instance of XMLHttpRequest in the browser and an instance of // http.ClientRequest in node.js @@ -102,7 +102,7 @@ const apiTooot = async ({ console.error( ctx.bold(' API tooot '), ctx.bold('internal'), - error.message, + error?.message, url ) return Promise.reject() diff --git a/src/components/Timeline/Shared/Actioned.tsx b/src/components/Timeline/Shared/Actioned.tsx index 47b59a9f..9b600d2f 100644 --- a/src/components/Timeline/Shared/Actioned.tsx +++ b/src/components/Timeline/Shared/Actioned.tsx @@ -22,7 +22,7 @@ const TimelineActioned = React.memo( const { colors } = useTheme() const navigation = useNavigation>() - const name = account.display_name || account.username + const name = account?.display_name || account.username const iconColor = colors.primaryDefault const content = (content: string) => ( diff --git a/src/i18n/zh-Hans/components/timeline.json b/src/i18n/zh-Hans/components/timeline.json index 60a57594..642bff69 100644 --- a/src/i18n/zh-Hans/components/timeline.json +++ b/src/i18n/zh-Hans/components/timeline.json @@ -101,7 +101,7 @@ "accessibilityHint": "用户帐户名" } }, - "application": "发自{{application}}", + "application": "发自 {{application}}", "edited": { "accessibilityLabel": "嘟文已编辑" }, diff --git a/src/screens/Compose.tsx b/src/screens/Compose.tsx index 712e31db..a848b695 100644 --- a/src/screens/Compose.tsx +++ b/src/screens/Compose.tsx @@ -354,7 +354,7 @@ const ScreenCompose: React.FC> = ({ navigation.goBack() }) .catch(error => { - if (error.removeReply) { + if (error?.removeReply) { Alert.alert( t('heading.right.alert.removeReply.title'), t('heading.right.alert.removeReply.description'), @@ -377,7 +377,12 @@ const ScreenCompose: React.FC> = ({ ] ) } else { - Sentry.Native.captureMessage('Compose posting', error) + Sentry.Native.captureMessage('Compose posting', { + contexts: { + errorObject: error, + errorString: error.toString() + } + }) haptics('Error') composeDispatch({ type: 'posting', payload: false }) Alert.alert(t('heading.right.alert.default.title'), undefined, [ diff --git a/src/screens/Tabs/Me/Root/Settings.tsx b/src/screens/Tabs/Me/Root/Settings.tsx index 5e08d0f5..d7687db4 100644 --- a/src/screens/Tabs/Me/Root/Settings.tsx +++ b/src/screens/Tabs/Me/Root/Settings.tsx @@ -28,7 +28,8 @@ const Settings: React.FC = () => { onPress={() => WebBrowser.openAuthSessionAsync( `https://${url}/settings/preferences`, - '' + 'tooot://tooot', + { dismissButtonStyle: 'done', readerMode: false } ) } /> diff --git a/src/screens/Tabs/Me/Settings/Tooot.tsx b/src/screens/Tabs/Me/Settings/Tooot.tsx index d1ff4f87..e1c7087a 100644 --- a/src/screens/Tabs/Me/Settings/Tooot.tsx +++ b/src/screens/Tabs/Me/Settings/Tooot.tsx @@ -64,8 +64,8 @@ const SettingsTooot: React.FC = () => { iconBack='ChevronRight' onPress={() => { analytics('settings_review_press') - StoreReview.isAvailableAsync().then(() => - StoreReview.requestReview() + StoreReview?.isAvailableAsync().then(() => + StoreReview?.requestReview() ) }} /> diff --git a/src/screens/Tabs/Shared/Toot.tsx b/src/screens/Tabs/Shared/Toot.tsx index fb1f4d1d..63a6a6ea 100644 --- a/src/screens/Tabs/Shared/Toot.tsx +++ b/src/screens/Tabs/Shared/Toot.tsx @@ -35,7 +35,7 @@ const TabSharedToot: React.FC> = ({ result.data.pages.flatMap(d => [...d.body]) : [] // Auto go back when toot page is empty - if (flattenData.length === 0) { + if (flattenData.length < 1) { navigation.goBack() return } @@ -46,13 +46,14 @@ const TabSharedToot: React.FC> = ({ if (pointer < 1) return try { setTimeout(() => { - console.log('scrolling') flRef.current?.scrollToIndex({ index: pointer, viewOffset: 100 }) }, 500) - } catch {} + } catch (error) { + return + } } } }) diff --git a/src/startup/netInfo.ts b/src/startup/netInfo.ts index 55a7fc68..21188668 100644 --- a/src/startup/netInfo.ts +++ b/src/startup/netInfo.ts @@ -41,10 +41,10 @@ const netInfo = async (): Promise<{ }).then(res => res.body) } catch (error: any) { log('error', 'netInfo', 'local credential check failed') - if (error.status && error.status == 401) { + if (error?.status && error.status == 401) { store.dispatch(removeInstance(instance)) } - return Promise.resolve({ corrupted: error.data.error }) + return Promise.resolve({ corrupted: error.data?.error }) } log('log', 'netInfo', 'local credential check passed') diff --git a/src/startup/sentry.ts b/src/startup/sentry.ts index 507516ca..7d398c66 100644 --- a/src/startup/sentry.ts +++ b/src/startup/sentry.ts @@ -6,8 +6,9 @@ const sentry = () => { log('log', 'Sentry', 'initializing') Sentry.init({ dsn: 'https://53348b60ff844d52886e90251b3a5f41@o917354.ingest.sentry.io/6410576', - enableInExpoDevelopment: true, - debug: !isRelease + enableInExpoDevelopment: false, + debug: !isRelease, + autoSessionTracking: true }) } diff --git a/src/utils/push/useConnect.ts b/src/utils/push/useConnect.ts index 79f04f43..84174ea4 100644 --- a/src/utils/push/useConnect.ts +++ b/src/utils/push/useConnect.ts @@ -35,7 +35,7 @@ const pushUseConnect = ({ t, instances }: Params) => { url: `push/connect/${expoToken}`, sentry: true }).catch(error => { - if (error.status == 404) { + if (error?.status == 404) { displayMessage({ theme, type: 'error', diff --git a/src/utils/slices/contextsSlice.ts b/src/utils/slices/contextsSlice.ts index 65d7c2e1..b957f65c 100644 --- a/src/utils/slices/contextsSlice.ts +++ b/src/utils/slices/contextsSlice.ts @@ -41,7 +41,9 @@ const contextsSlice = createSlice({ if (Updates.releaseChannel.includes('release')) { state.storeReview.current = state.storeReview.current + action.payload if (state.storeReview.current === state.storeReview.context) { - StoreReview.isAvailableAsync().then(() => StoreReview.requestReview()) + StoreReview?.isAvailableAsync().then(() => + StoreReview.requestReview() + ) } } }, diff --git a/src/utils/slices/instancesSlice.ts b/src/utils/slices/instancesSlice.ts index 605c036a..85210dff 100644 --- a/src/utils/slices/instancesSlice.ts +++ b/src/utils/slices/instancesSlice.ts @@ -306,6 +306,7 @@ const instancesSlice = createSlice({ // Check if frequently used emojis still exist .addCase(checkEmojis.fulfilled, (state, action) => { + if (!action.payload || !action.payload.length) return const activeIndex = findInstanceActive(state.instances) state.instances[activeIndex].frequentEmojis = state.instances[ activeIndex