diff --git a/app/actions/app/global.ts b/app/actions/app/global.ts
index 3de806fb8..fde5c8d11 100644
--- a/app/actions/app/global.ts
+++ b/app/actions/app/global.ts
@@ -77,3 +77,11 @@ export const removeLastViewedChannelIdAndServer = async () => {
export const removeLastViewedThreadIdAndServer = async () => {
return storeGlobal(GLOBAL_IDENTIFIERS.LAST_VIEWED_THREAD, null, false);
};
+
+export const storePushDisabledInServerAcknowledged = async (serverUrl: string) => {
+ return storeGlobal(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverUrl}`, 'true', false);
+};
+
+export const removePushDisabledInServerAcknowledged = async (serverUrl: string) => {
+ return storeGlobal(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverUrl}`, null, false);
+};
diff --git a/app/constants/database.ts b/app/constants/database.ts
index f14d22a62..d302c280a 100644
--- a/app/constants/database.ts
+++ b/app/constants/database.ts
@@ -82,6 +82,7 @@ export const GLOBAL_IDENTIFIERS = {
ONBOARDING: 'onboarding',
LAST_VIEWED_CHANNEL: 'lastViewedChannel',
LAST_VIEWED_THREAD: 'lastViewedThread',
+ PUSH_DISABLED_ACK: 'pushDisabledAck',
};
export enum OperationType {
diff --git a/app/managers/session_manager.ts b/app/managers/session_manager.ts
index 0e21ca4a4..1ba1fbbb0 100644
--- a/app/managers/session_manager.ts
+++ b/app/managers/session_manager.ts
@@ -5,7 +5,7 @@ import CookieManager, {type Cookie} from '@react-native-cookies/cookies';
import {AppState, type AppStateStatus, DeviceEventEmitter, Platform} from 'react-native';
import FastImage from 'react-native-fast-image';
-import {storeOnboardingViewedValue} from '@actions/app/global';
+import {removePushDisabledInServerAcknowledged, storeOnboardingViewedValue} from '@actions/app/global';
import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session';
import {Events, Launch} from '@constants';
import DatabaseManager from '@database/manager';
@@ -22,6 +22,7 @@ import {getThemeFromState} from '@screens/navigation';
import EphemeralStore from '@store/ephemeral_store';
import {deleteFileCache, deleteFileCacheByDir} from '@utils/file';
import {isMainActivity} from '@utils/helpers';
+import {urlSafeBase64Encode} from '@utils/security';
import {addNewServer} from '@utils/server';
import type {LaunchType} from '@typings/launch';
@@ -121,6 +122,7 @@ class SessionManager {
WebsocketManager.invalidateClient(serverUrl);
if (removeServer) {
+ await removePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl));
await DatabaseManager.destroyServerDatabase(serverUrl);
} else {
await DatabaseManager.deleteServerDatabase(serverUrl);
diff --git a/app/queries/app/global.ts b/app/queries/app/global.ts
index 9784c6124..e1ff99bb8 100644
--- a/app/queries/app/global.ts
+++ b/app/queries/app/global.ts
@@ -55,6 +55,22 @@ export const getDontAskForReview = async () => {
return Boolean(records?.[0]?.value);
};
+export const getPushDisabledInServerAcknowledged = async (serverDomainString: string) => {
+ const records = await queryGlobalValue(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverDomainString}`)?.fetch();
+ return Boolean(records?.[0]?.value);
+};
+
+export const observePushDisabledInServerAcknowledged = (serverDomainString: string) => {
+ const query = queryGlobalValue(`${GLOBAL_IDENTIFIERS.PUSH_DISABLED_ACK}${serverDomainString}`);
+ if (!query) {
+ return of$(false);
+ }
+ return query.observe().pipe(
+ switchMap((result) => (result.length ? result[0].observe() : of$(false))),
+ switchMap((v) => of$(Boolean(v))),
+ );
+};
+
export const getFirstLaunch = async () => {
const records = await queryGlobalValue(GLOBAL_IDENTIFIERS.FIRST_LAUNCH)?.fetch();
if (!records?.[0]?.value) {
diff --git a/app/screens/home/channel_list/categories_list/header/header.test.tsx b/app/screens/home/channel_list/categories_list/header/header.test.tsx
index 2832e7f3d..7299f0c98 100644
--- a/app/screens/home/channel_list/categories_list/header/header.test.tsx
+++ b/app/screens/home/channel_list/categories_list/header/header.test.tsx
@@ -3,7 +3,7 @@
import React from 'react';
-import {PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
+import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
import {renderWithIntl} from '@test/intl-test-helper';
import Header from './header';
@@ -22,4 +22,18 @@ describe('components/channel_list/header', () => {
expect(toJSON()).toMatchSnapshot();
});
+
+ it('Push notifications disabled show alert icon', () => {
+ const wrapper = renderWithIntl(
+ ,
+ );
+
+ expect(wrapper.getByTestId('channel_list_header.push_alert')).toBeTruthy();
+ });
});
diff --git a/app/screens/home/channel_list/categories_list/header/header.tsx b/app/screens/home/channel_list/categories_list/header/header.tsx
index 4cec3fde3..ca2840642 100644
--- a/app/screens/home/channel_list/categories_list/header/header.tsx
+++ b/app/screens/home/channel_list/categories_list/header/header.tsx
@@ -206,7 +206,7 @@ const ChannelListHeader = ({
>
{serverDisplayName}
- {(pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED) && (
+ {pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && (
{
+ if (buttonIndex === 0 && serverUrl) {
+ // User clicked "Okay" acknowledging that the push notifications are disabled on that server
+ await storePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl));
+ }
+};
+
+export function alertPushProxyError(intl: IntlShape, serverUrl?: string) {
Alert.alert(
intl.formatMessage({
id: 'alert.push_proxy_error.title',
@@ -31,10 +51,11 @@ export function alertPushProxyError(intl: IntlShape) {
}),
intl.formatMessage({
id: 'alert.push_proxy_error.description',
- defaultMessage: 'Due to the configuration for this server, notifications cannot be received in the mobile app. Contact your system admin for more information.',
+ defaultMessage: 'Due to the configuration of this server, notifications cannot be received in the mobile app. Contact your system admin for more information.',
}),
[{
text: intl.formatMessage({id: 'alert.push_proxy.button', defaultMessage: 'Okay'}),
+ onPress: () => handleAlertResponse(0, serverUrl),
}],
);
}
diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json
index 6c656d9bd..0f93b5a28 100644
--- a/assets/base/i18n/en.json
+++ b/assets/base/i18n/en.json
@@ -15,7 +15,7 @@
"account.your_profile": "Your Profile",
"alert.channel_deleted.description": "The channel {displayName} has been archived.",
"alert.channel_deleted.title": "Archived channel",
- "alert.push_proxy_error.description": "Due to the configuration for this server, notifications cannot be received in the mobile app. Contact your system admin for more information.",
+ "alert.push_proxy_error.description": "Due to the configuration of this server, notifications cannot be received in the mobile app. Contact your system admin for more information.",
"alert.push_proxy_error.title": "Notifications cannot be received from this server",
"alert.push_proxy_unknown.description": "This server was unable to receive push notifications for an unknown reason. This will be attempted again next time you connect.",
"alert.push_proxy_unknown.title": "Notifications could not be received from this server",
diff --git a/assets/base/i18n/en_AU.json b/assets/base/i18n/en_AU.json
index e6dbf6303..b0f133bc0 100644
--- a/assets/base/i18n/en_AU.json
+++ b/assets/base/i18n/en_AU.json
@@ -686,7 +686,7 @@
"alert.push_proxy.button": "Okay",
"alert.push_proxy_unknown.title": "Notifications could not be received from this server",
"alert.push_proxy_error.title": "Notifications cannot be received from this server",
- "alert.push_proxy_error.description": "Due to the configuration for this server, notifications cannot be received in the mobile app. Contact your system admin for more information.",
+ "alert.push_proxy_error.description": "Due to the configuration of this server, notifications cannot be received in the mobile app. Contact your system admin for more information.",
"alert.channel_deleted.title": "Archived channel",
"alert.channel_deleted.description": "The channel {displayName} has been archived.",
"account.your_profile": "Your Profile",