From 0da1b5c6a434a71e78181e89f23e90d686798d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Wed, 9 Aug 2023 19:52:37 +0200 Subject: [PATCH 01/23] MM-50354 - do not show push disabled notification once acknowledged --- app/actions/app/global.ts | 8 ++++ app/constants/database.ts | 1 + app/managers/session_manager.ts | 6 ++- app/queries/app/global.ts | 16 +++++++ .../categories_list/header/header.test.tsx | 1 + .../categories_list/header/header.tsx | 6 ++- .../categories_list/header/index.ts | 12 +++++- .../servers/servers_list/server_item/index.ts | 4 +- .../servers_list/server_item/server_item.tsx | 4 +- app/utils/helpers.ts | 42 +++++++++++++++++++ app/utils/push_proxy.ts | 28 +++++++++++-- 11 files changed, 117 insertions(+), 11 deletions(-) diff --git a/app/actions/app/global.ts b/app/actions/app/global.ts index bb98cd5db..c258ba8a3 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..c79a69cff 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'; @@ -21,7 +21,7 @@ import {getCurrentUser} from '@queries/servers/user'; import {getThemeFromState} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {deleteFileCache, deleteFileCacheByDir} from '@utils/file'; -import {isMainActivity} from '@utils/helpers'; +import {extractCleanDomain, isMainActivity} from '@utils/helpers'; import {addNewServer} from '@utils/server'; import type {LaunchType} from '@typings/launch'; @@ -168,6 +168,8 @@ class SessionManager { await this.terminateSession(serverUrl, removeServer); + await removePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)); + if (activeServerUrl === serverUrl) { let displayName = ''; let launchType: LaunchType = Launch.AddServer; 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..af40f111a 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 @@ -17,6 +17,7 @@ describe('components/channel_list/header', () => { canJoinChannels={true} canInvitePeople={true} displayName={'Test!'} + pushDisabledAck={true} />, ); 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..fb1528d9b 100644 --- a/app/screens/home/channel_list/categories_list/header/header.tsx +++ b/app/screens/home/channel_list/categories_list/header/header.tsx @@ -38,6 +38,7 @@ type Props = { iconPad?: boolean; onHeaderPress?: () => void; pushProxyStatus: string; + pushDisabledAck: boolean; } const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -111,6 +112,7 @@ const ChannelListHeader = ({ iconPad, onHeaderPress, pushProxyStatus, + pushDisabledAck, }: Props) => { const theme = useTheme(); const isTablet = useIsTablet(); @@ -166,7 +168,7 @@ const ChannelListHeader = ({ const onPushAlertPress = useCallback(() => { if (pushProxyStatus === PUSH_PROXY_STATUS_NOT_AVAILABLE) { - alertPushProxyError(intl); + alertPushProxyError(intl, serverUrl); } else { alertPushProxyUnknown(intl); } @@ -206,7 +208,7 @@ const ChannelListHeader = ({ > {serverDisplayName} - {(pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED) && ( + {pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && ( { +type Props = WithDatabaseArgs & { + serverUrl: string; +} + +const enhanced = withObservables([], ({serverUrl, database}: Props) => { const team = observeCurrentTeam(database); const currentUser = observeCurrentUser(database); @@ -57,7 +64,8 @@ const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { distinctUntilChanged(), ), pushProxyStatus: observePushVerificationStatus(database), + pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)), }; }); -export default withDatabase(enhanced(ChannelListHeader)); +export default withDatabase(withServerUrl(enhanced(ChannelListHeader))); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts index a46828e71..626f5121d 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts +++ b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts @@ -4,10 +4,11 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; +import {extractCleanDomain} from '@app/utils/helpers'; import {Tutorial} from '@constants'; import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy'; import DatabaseManager from '@database/manager'; -import {observeTutorialWatched} from '@queries/app/global'; +import {observePushDisabledInServerAcknowledged, observeTutorialWatched} from '@queries/app/global'; import {observePushVerificationStatus} from '@queries/servers/system'; import ServerItem from './server_item'; @@ -26,6 +27,7 @@ const enhance = withObservables(['highlight'], ({highlight, server}: {highlight: server: server.observe(), tutorialWatched, pushProxyStatus: serverDatabase ? observePushVerificationStatus(serverDatabase) : of$(PUSH_PROXY_STATUS_UNKNOWN), + pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(server.url)), }; }); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx index efe10083e..0f463cba6 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx +++ b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx @@ -44,6 +44,7 @@ type Props = { server: ServersModel; tutorialWatched: boolean; pushProxyStatus: string; + pushDisabledAck: boolean; } type BadgeValues = { @@ -147,6 +148,7 @@ const ServerItem = ({ server, tutorialWatched, pushProxyStatus, + pushDisabledAck, }: Props) => { const intl = useIntl(); const theme = useTheme(); @@ -428,7 +430,7 @@ const ServerItem = ({ > {displayName} - {server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && ( + {server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && ( Result: example-something + * // Input: http://192.168.1.1 => Result: 192.168.1.1 + * // Input: https://127.0.0.1:3000 => Result: 127.0.0.1 + */ +export function extractDomain(input: string) { + const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?$/; + const match = input.match(regex); + + if (match && match[2]) { + return match[2].replace(/[\W.]/g, ''); + } + + return ''; +} + +/** + * Returns the domain name or IP address from a serverUrl without special characters. + * + * @param {string} domain - The extracted domain from a serverUrl. + * @returns {string} The extracted domain name or IP address, modified to remove special characters, + * or empty . + * + * // Output: + * // Input: example-something => Result: examplesomething + * // Input: 192.168.1.1 => Result: 19216811 + * // Input: 127.0.0.1 => Result: 127001 + */ +export function extractCleanDomain(domain: string) { + if (!domain) { + return ''; + } + return extractDomain(domain).replace(/[\W.]/g, ''); +} diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index e207c9841..7bfba76c2 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -3,16 +3,30 @@ import {Alert} from 'react-native'; +import {storePushDisabledInServerAcknowledged} from '@actions/app/global'; +import {getPushDisabledInServerAcknowledged} from '@app/queries/app/global'; import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy'; import EphemeralStore from '@store/ephemeral_store'; +import {extractCleanDomain} from './helpers'; + import type {IntlShape} from 'react-intl'; -export function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) { +export async function pushDisabledInServerAck(serverUrl: string) { + const extractedDomain = extractCleanDomain(serverUrl); + const pushServerDisabledAck = await getPushDisabledInServerAcknowledged(extractedDomain); + return pushServerDisabledAck; +} + +export async function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) { + const a = await pushDisabledInServerAck(serverUrl); + switch (verification) { case PUSH_PROXY_RESPONSE_NOT_AVAILABLE: EphemeralStore.setPushProxyVerificationState(serverUrl, PUSH_PROXY_STATUS_NOT_AVAILABLE); - alertPushProxyError(intl); + if (!a) { + alertPushProxyError(intl, serverUrl); + } break; case PUSH_PROXY_RESPONSE_UNKNOWN: EphemeralStore.setPushProxyVerificationState(serverUrl, PUSH_PROXY_STATUS_UNKNOWN); @@ -23,7 +37,14 @@ export function canReceiveNotifications(serverUrl: string, verification: string, } } -export function alertPushProxyError(intl: IntlShape) { +const handleAlertResponse = async (buttonIndex: number, serverUrl: string) => { + if (buttonIndex === 0) { + // User clicked "Okay" acknowledging that the push notifications are disabled on that server + await storePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)); + } +}; + +export function alertPushProxyError(intl: IntlShape, serverUrl: string) { Alert.alert( intl.formatMessage({ id: 'alert.push_proxy_error.title', @@ -35,6 +56,7 @@ export function alertPushProxyError(intl: IntlShape) { }), [{ text: intl.formatMessage({id: 'alert.push_proxy.button', defaultMessage: 'Okay'}), + onPress: () => handleAlertResponse(0, serverUrl), }], ); } From 7d3115c92043a75b7d9a759cb2b9e3e20232a7c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Thu, 10 Aug 2023 13:53:27 +0200 Subject: [PATCH 02/23] enhance regular expression to support optional subpath --- app/utils/helpers.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/utils/helpers.ts b/app/utils/helpers.ts index d464492ff..715951d38 100644 --- a/app/utils/helpers.ts +++ b/app/utils/helpers.ts @@ -174,13 +174,16 @@ export function isMainActivity() { * // Input: https://example-something.com => Result: example-something * // Input: http://192.168.1.1 => Result: 192.168.1.1 * // Input: https://127.0.0.1:3000 => Result: 127.0.0.1 + * // Input: https://subdomain.example.com/api => subdomain.example.com/api + * // Input: http://localhost:8080/app/v1 => localhost:8080/app/v1 */ export function extractDomain(input: string) { - const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?$/; + const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?(\/\S*)?/; const match = input.match(regex); - if (match && match[2]) { - return match[2].replace(/[\W.]/g, ''); + if (match) { + const modifiedString = match[2] + (match[4] || ''); + return modifiedString; } return ''; From 7244f95fea86ebd3866a68edb8cc36d871738b79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Mon, 21 Aug 2023 17:31:16 +0200 Subject: [PATCH 03/23] add unit test; refactor function; not remove on logout but on server remove --- app/managers/session_manager.ts | 5 +-- .../categories_list/header/header.test.tsx | 32 +++++++++++++++- .../categories_list/header/index.ts | 4 +- .../servers/servers_list/server_item/index.ts | 4 +- app/utils/helpers.ts | 37 +++++-------------- app/utils/push_proxy.ts | 10 ++--- 6 files changed, 51 insertions(+), 41 deletions(-) diff --git a/app/managers/session_manager.ts b/app/managers/session_manager.ts index c79a69cff..09b0c1301 100644 --- a/app/managers/session_manager.ts +++ b/app/managers/session_manager.ts @@ -21,7 +21,7 @@ import {getCurrentUser} from '@queries/servers/user'; import {getThemeFromState} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {deleteFileCache, deleteFileCacheByDir} from '@utils/file'; -import {extractCleanDomain, isMainActivity} from '@utils/helpers'; +import {createKeyFromServerUrl, isMainActivity} from '@utils/helpers'; import {addNewServer} from '@utils/server'; import type {LaunchType} from '@typings/launch'; @@ -121,6 +121,7 @@ class SessionManager { WebsocketManager.invalidateClient(serverUrl); if (removeServer) { + await removePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)); await DatabaseManager.destroyServerDatabase(serverUrl); } else { await DatabaseManager.deleteServerDatabase(serverUrl); @@ -168,8 +169,6 @@ class SessionManager { await this.terminateSession(serverUrl, removeServer); - await removePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)); - if (activeServerUrl === serverUrl) { let displayName = ''; let launchType: LaunchType = Launch.AddServer; 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 af40f111a..5959534ca 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'; @@ -23,4 +23,34 @@ describe('components/channel_list/header', () => { expect(toJSON()).toMatchSnapshot(); }); + + it('Push notifications disabled and not having ackoledge show alert icon', () => { + const wrapper = renderWithIntl( +
, + ); + + expect(wrapper.getByTestId('channel_list_header.push_alert')).toBeTruthy(); + }); + + it('Push notifications disabled but after ackoledging do not show alert icon', () => { + const wrapper = renderWithIntl( +
, + ); + + expect(wrapper.queryByTestId('channel_list_header.push_alert')).toBeNull(); + }); }); diff --git a/app/screens/home/channel_list/categories_list/header/index.ts b/app/screens/home/channel_list/categories_list/header/index.ts index 305883204..8d72dda1a 100644 --- a/app/screens/home/channel_list/categories_list/header/index.ts +++ b/app/screens/home/channel_list/categories_list/header/index.ts @@ -7,7 +7,7 @@ import {combineLatest, of as of$} from 'rxjs'; import {distinctUntilChanged, switchMap} from 'rxjs/operators'; import {observePushDisabledInServerAcknowledged} from '@app/queries/app/global'; -import {extractCleanDomain} from '@app/utils/helpers'; +import {createKeyFromServerUrl} from '@app/utils/helpers'; import {Permissions} from '@constants'; import {withServerUrl} from '@context/server'; import {observePermissionForTeam} from '@queries/servers/role'; @@ -64,7 +64,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => { distinctUntilChanged(), ), pushProxyStatus: observePushVerificationStatus(database), - pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)), + pushDisabledAck: observePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)), }; }); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts index 626f5121d..dd0d83ff0 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts +++ b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts @@ -4,7 +4,7 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; -import {extractCleanDomain} from '@app/utils/helpers'; +import {createKeyFromServerUrl} from '@app/utils/helpers'; import {Tutorial} from '@constants'; import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy'; import DatabaseManager from '@database/manager'; @@ -27,7 +27,7 @@ const enhance = withObservables(['highlight'], ({highlight, server}: {highlight: server: server.observe(), tutorialWatched, pushProxyStatus: serverDatabase ? observePushVerificationStatus(serverDatabase) : of$(PUSH_PROXY_STATUS_UNKNOWN), - pushDisabledAck: observePushDisabledInServerAcknowledged(extractCleanDomain(server.url)), + pushDisabledAck: observePushDisabledInServerAcknowledged(createKeyFromServerUrl(server.url)), }; }); diff --git a/app/utils/helpers.ts b/app/utils/helpers.ts index 715951d38..dabfafd30 100644 --- a/app/utils/helpers.ts +++ b/app/utils/helpers.ts @@ -164,46 +164,27 @@ export function isMainActivity() { } /** - * Extracts the domain name or IP address from a serverUrl. + * Uses the serverUrl to create a key. * * @param {string} input - The serverUrl, potentially with a port and protocol. * @returns {string} The extracted domain name or IP address, * or empty if no match is found. * * // Output: - * // Input: https://example-something.com => Result: example-something - * // Input: http://192.168.1.1 => Result: 192.168.1.1 - * // Input: https://127.0.0.1:3000 => Result: 127.0.0.1 - * // Input: https://subdomain.example.com/api => subdomain.example.com/api - * // Input: http://localhost:8080/app/v1 => localhost:8080/app/v1 + * // Input: https://example-something.com => Result: examplesomething + * // Input: http://192.168.1.1 => Result: 19216811 + * // Input: https://127.0.0.1:3000 => Result: 1270013000 + * // Input: https://subdomain.example.com/api => subdomainexamplecomapi + * // Input: http://localhost:8080/app/v1 => localhost8080appv1 */ -export function extractDomain(input: string) { +export function createKeyFromServerUrl(input: string) { const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?(\/\S*)?/; const match = input.match(regex); if (match) { - const modifiedString = match[2] + (match[4] || ''); - return modifiedString; + const domainWithPortAndSubpath = match[2] + (match[3] || '') + (match[4] || ''); + return domainWithPortAndSubpath.replace(/[^\w]/g, ''); } return ''; } - -/** - * Returns the domain name or IP address from a serverUrl without special characters. - * - * @param {string} domain - The extracted domain from a serverUrl. - * @returns {string} The extracted domain name or IP address, modified to remove special characters, - * or empty . - * - * // Output: - * // Input: example-something => Result: examplesomething - * // Input: 192.168.1.1 => Result: 19216811 - * // Input: 127.0.0.1 => Result: 127001 - */ -export function extractCleanDomain(domain: string) { - if (!domain) { - return ''; - } - return extractDomain(domain).replace(/[\W.]/g, ''); -} diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index 7bfba76c2..e44a35882 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -8,23 +8,23 @@ import {getPushDisabledInServerAcknowledged} from '@app/queries/app/global'; import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy'; import EphemeralStore from '@store/ephemeral_store'; -import {extractCleanDomain} from './helpers'; +import {createKeyFromServerUrl} from './helpers'; import type {IntlShape} from 'react-intl'; export async function pushDisabledInServerAck(serverUrl: string) { - const extractedDomain = extractCleanDomain(serverUrl); + const extractedDomain = createKeyFromServerUrl(serverUrl); const pushServerDisabledAck = await getPushDisabledInServerAcknowledged(extractedDomain); return pushServerDisabledAck; } export async function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) { - const a = await pushDisabledInServerAck(serverUrl); + const hasAckNotification = await pushDisabledInServerAck(serverUrl); switch (verification) { case PUSH_PROXY_RESPONSE_NOT_AVAILABLE: EphemeralStore.setPushProxyVerificationState(serverUrl, PUSH_PROXY_STATUS_NOT_AVAILABLE); - if (!a) { + if (!hasAckNotification) { alertPushProxyError(intl, serverUrl); } break; @@ -40,7 +40,7 @@ export async function canReceiveNotifications(serverUrl: string, verification: s const handleAlertResponse = async (buttonIndex: number, serverUrl: string) => { if (buttonIndex === 0) { // User clicked "Okay" acknowledging that the push notifications are disabled on that server - await storePushDisabledInServerAcknowledged(extractCleanDomain(serverUrl)); + await storePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)); } }; From d4cd0cb1de50d13838647f0d4ef2d7d5179ac658 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Tue, 22 Aug 2023 15:50:45 +0200 Subject: [PATCH 04/23] implement pr feedback; reuse existing keyfromurl function; fix imports --- app/managers/session_manager.ts | 5 ++-- .../categories_list/header/header.test.tsx | 4 +-- .../categories_list/header/index.ts | 6 ++--- .../servers/servers_list/server_item/index.ts | 4 +-- app/utils/helpers.ts | 26 ------------------- app/utils/push_proxy.ts | 13 +++++----- 6 files changed, 16 insertions(+), 42 deletions(-) diff --git a/app/managers/session_manager.ts b/app/managers/session_manager.ts index 09b0c1301..f5bbe2562 100644 --- a/app/managers/session_manager.ts +++ b/app/managers/session_manager.ts @@ -7,6 +7,7 @@ import FastImage from 'react-native-fast-image'; import {removePushDisabledInServerAcknowledged, storeOnboardingViewedValue} from '@actions/app/global'; import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session'; +import {urlSafeBase64Encode} from '@app/utils/security'; import {Events, Launch} from '@constants'; import DatabaseManager from '@database/manager'; import {resetMomentLocale} from '@i18n'; @@ -21,7 +22,7 @@ import {getCurrentUser} from '@queries/servers/user'; import {getThemeFromState} from '@screens/navigation'; import EphemeralStore from '@store/ephemeral_store'; import {deleteFileCache, deleteFileCacheByDir} from '@utils/file'; -import {createKeyFromServerUrl, isMainActivity} from '@utils/helpers'; +import {isMainActivity} from '@utils/helpers'; import {addNewServer} from '@utils/server'; import type {LaunchType} from '@typings/launch'; @@ -121,7 +122,7 @@ class SessionManager { WebsocketManager.invalidateClient(serverUrl); if (removeServer) { - await removePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)); + await removePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl)); await DatabaseManager.destroyServerDatabase(serverUrl); } else { await DatabaseManager.deleteServerDatabase(serverUrl); 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 5959534ca..8414a7a71 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 @@ -24,7 +24,7 @@ describe('components/channel_list/header', () => { expect(toJSON()).toMatchSnapshot(); }); - it('Push notifications disabled and not having ackoledge show alert icon', () => { + it('Push notifications disabled and not having acknoledged it show alert icon', () => { const wrapper = renderWithIntl(
{ expect(wrapper.getByTestId('channel_list_header.push_alert')).toBeTruthy(); }); - it('Push notifications disabled but after ackoledging do not show alert icon', () => { + it('Push notifications are disabled, but even after acknowledging them, the alert icon does not appear', () => { const wrapper = renderWithIntl(
{ distinctUntilChanged(), ), pushProxyStatus: observePushVerificationStatus(database), - pushDisabledAck: observePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)), + pushDisabledAck: observePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl)), }; }); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts index dd0d83ff0..be9090cc2 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts +++ b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts @@ -4,12 +4,12 @@ import withObservables from '@nozbe/with-observables'; import {of as of$} from 'rxjs'; -import {createKeyFromServerUrl} from '@app/utils/helpers'; import {Tutorial} from '@constants'; import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy'; import DatabaseManager from '@database/manager'; import {observePushDisabledInServerAcknowledged, observeTutorialWatched} from '@queries/app/global'; import {observePushVerificationStatus} from '@queries/servers/system'; +import {urlSafeBase64Encode} from '@utils/security'; import ServerItem from './server_item'; @@ -27,7 +27,7 @@ const enhance = withObservables(['highlight'], ({highlight, server}: {highlight: server: server.observe(), tutorialWatched, pushProxyStatus: serverDatabase ? observePushVerificationStatus(serverDatabase) : of$(PUSH_PROXY_STATUS_UNKNOWN), - pushDisabledAck: observePushDisabledInServerAcknowledged(createKeyFromServerUrl(server.url)), + pushDisabledAck: observePushDisabledInServerAcknowledged(urlSafeBase64Encode(server.url)), }; }); diff --git a/app/utils/helpers.ts b/app/utils/helpers.ts index dabfafd30..cb1915c0c 100644 --- a/app/utils/helpers.ts +++ b/app/utils/helpers.ts @@ -162,29 +162,3 @@ export function isMainActivity() { android: ShareModule?.getCurrentActivityName() === 'MainActivity', }); } - -/** - * Uses the serverUrl to create a key. - * - * @param {string} input - The serverUrl, potentially with a port and protocol. - * @returns {string} The extracted domain name or IP address, - * or empty if no match is found. - * - * // Output: - * // Input: https://example-something.com => Result: examplesomething - * // Input: http://192.168.1.1 => Result: 19216811 - * // Input: https://127.0.0.1:3000 => Result: 1270013000 - * // Input: https://subdomain.example.com/api => subdomainexamplecomapi - * // Input: http://localhost:8080/app/v1 => localhost8080appv1 - */ -export function createKeyFromServerUrl(input: string) { - const regex = /^(https?:\/\/)?([\w.-]+)(:\d+)?(\/\S*)?/; - const match = input.match(regex); - - if (match) { - const domainWithPortAndSubpath = match[2] + (match[3] || '') + (match[4] || ''); - return domainWithPortAndSubpath.replace(/[^\w]/g, ''); - } - - return ''; -} diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index e44a35882..9ce7cb80a 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -4,18 +4,17 @@ import {Alert} from 'react-native'; import {storePushDisabledInServerAcknowledged} from '@actions/app/global'; -import {getPushDisabledInServerAcknowledged} from '@app/queries/app/global'; import {PUSH_PROXY_RESPONSE_NOT_AVAILABLE, PUSH_PROXY_RESPONSE_UNKNOWN, PUSH_PROXY_STATUS_NOT_AVAILABLE, PUSH_PROXY_STATUS_UNKNOWN, PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy'; +import {getPushDisabledInServerAcknowledged} from '@queries/app/global'; import EphemeralStore from '@store/ephemeral_store'; -import {createKeyFromServerUrl} from './helpers'; +import {urlSafeBase64Encode} from './security'; import type {IntlShape} from 'react-intl'; -export async function pushDisabledInServerAck(serverUrl: string) { - const extractedDomain = createKeyFromServerUrl(serverUrl); - const pushServerDisabledAck = await getPushDisabledInServerAcknowledged(extractedDomain); - return pushServerDisabledAck; +export function pushDisabledInServerAck(serverUrl: string) { + const extractedDomain = urlSafeBase64Encode(serverUrl); + return getPushDisabledInServerAcknowledged(extractedDomain); } export async function canReceiveNotifications(serverUrl: string, verification: string, intl: IntlShape) { @@ -40,7 +39,7 @@ export async function canReceiveNotifications(serverUrl: string, verification: s const handleAlertResponse = async (buttonIndex: number, serverUrl: string) => { if (buttonIndex === 0) { // User clicked "Okay" acknowledging that the push notifications are disabled on that server - await storePushDisabledInServerAcknowledged(createKeyFromServerUrl(serverUrl)); + await storePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl)); } }; From 41ca61966bcf035fb692d5988e401f154fb9b5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Tue, 10 Oct 2023 17:10:44 +0200 Subject: [PATCH 05/23] do not remove inside app alerts --- app/managers/session_manager.ts | 2 +- .../categories_list/header/header.test.tsx | 19 +------------------ .../categories_list/header/header.tsx | 6 ++---- .../categories_list/header/index.ts | 12 ++---------- .../servers/servers_list/server_item/index.ts | 4 +--- .../servers_list/server_item/server_item.tsx | 4 +--- app/utils/push_proxy.ts | 6 +++--- 7 files changed, 11 insertions(+), 42 deletions(-) diff --git a/app/managers/session_manager.ts b/app/managers/session_manager.ts index f5bbe2562..1ba1fbbb0 100644 --- a/app/managers/session_manager.ts +++ b/app/managers/session_manager.ts @@ -7,7 +7,6 @@ import FastImage from 'react-native-fast-image'; import {removePushDisabledInServerAcknowledged, storeOnboardingViewedValue} from '@actions/app/global'; import {cancelSessionNotification, logout, scheduleSessionNotification} from '@actions/remote/session'; -import {urlSafeBase64Encode} from '@app/utils/security'; import {Events, Launch} from '@constants'; import DatabaseManager from '@database/manager'; import {resetMomentLocale} from '@i18n'; @@ -23,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'; 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 8414a7a71..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 @@ -17,14 +17,13 @@ describe('components/channel_list/header', () => { canJoinChannels={true} canInvitePeople={true} displayName={'Test!'} - pushDisabledAck={true} />, ); expect(toJSON()).toMatchSnapshot(); }); - it('Push notifications disabled and not having acknoledged it show alert icon', () => { + it('Push notifications disabled show alert icon', () => { const wrapper = renderWithIntl(
{ canJoinChannels={true} canInvitePeople={true} displayName={'Test!'} - pushDisabledAck={false} />, ); expect(wrapper.getByTestId('channel_list_header.push_alert')).toBeTruthy(); }); - - it('Push notifications are disabled, but even after acknowledging them, the alert icon does not appear', () => { - const wrapper = renderWithIntl( -
, - ); - - expect(wrapper.queryByTestId('channel_list_header.push_alert')).toBeNull(); - }); }); 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 fb1528d9b..ca2840642 100644 --- a/app/screens/home/channel_list/categories_list/header/header.tsx +++ b/app/screens/home/channel_list/categories_list/header/header.tsx @@ -38,7 +38,6 @@ type Props = { iconPad?: boolean; onHeaderPress?: () => void; pushProxyStatus: string; - pushDisabledAck: boolean; } const getStyles = makeStyleSheetFromTheme((theme: Theme) => ({ @@ -112,7 +111,6 @@ const ChannelListHeader = ({ iconPad, onHeaderPress, pushProxyStatus, - pushDisabledAck, }: Props) => { const theme = useTheme(); const isTablet = useIsTablet(); @@ -168,7 +166,7 @@ const ChannelListHeader = ({ const onPushAlertPress = useCallback(() => { if (pushProxyStatus === PUSH_PROXY_STATUS_NOT_AVAILABLE) { - alertPushProxyError(intl, serverUrl); + alertPushProxyError(intl); } else { alertPushProxyUnknown(intl); } @@ -208,7 +206,7 @@ const ChannelListHeader = ({ > {serverDisplayName} - {pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && ( + {pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && ( { +const enhanced = withObservables([], ({database}: WithDatabaseArgs) => { const team = observeCurrentTeam(database); const currentUser = observeCurrentUser(database); @@ -64,8 +57,7 @@ const enhanced = withObservables([], ({serverUrl, database}: Props) => { distinctUntilChanged(), ), pushProxyStatus: observePushVerificationStatus(database), - pushDisabledAck: observePushDisabledInServerAcknowledged(urlSafeBase64Encode(serverUrl)), }; }); -export default withDatabase(withServerUrl(enhanced(ChannelListHeader))); +export default withDatabase(enhanced(ChannelListHeader)); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts index be9090cc2..a46828e71 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/index.ts +++ b/app/screens/home/channel_list/servers/servers_list/server_item/index.ts @@ -7,9 +7,8 @@ import {of as of$} from 'rxjs'; import {Tutorial} from '@constants'; import {PUSH_PROXY_STATUS_UNKNOWN} from '@constants/push_proxy'; import DatabaseManager from '@database/manager'; -import {observePushDisabledInServerAcknowledged, observeTutorialWatched} from '@queries/app/global'; +import {observeTutorialWatched} from '@queries/app/global'; import {observePushVerificationStatus} from '@queries/servers/system'; -import {urlSafeBase64Encode} from '@utils/security'; import ServerItem from './server_item'; @@ -27,7 +26,6 @@ const enhance = withObservables(['highlight'], ({highlight, server}: {highlight: server: server.observe(), tutorialWatched, pushProxyStatus: serverDatabase ? observePushVerificationStatus(serverDatabase) : of$(PUSH_PROXY_STATUS_UNKNOWN), - pushDisabledAck: observePushDisabledInServerAcknowledged(urlSafeBase64Encode(server.url)), }; }); diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx index 0f463cba6..efe10083e 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx +++ b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx @@ -44,7 +44,6 @@ type Props = { server: ServersModel; tutorialWatched: boolean; pushProxyStatus: string; - pushDisabledAck: boolean; } type BadgeValues = { @@ -148,7 +147,6 @@ const ServerItem = ({ server, tutorialWatched, pushProxyStatus, - pushDisabledAck, }: Props) => { const intl = useIntl(); const theme = useTheme(); @@ -430,7 +428,7 @@ const ServerItem = ({ > {displayName} - {server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && !pushDisabledAck && ( + {server.lastActiveAt > 0 && pushProxyStatus !== PUSH_PROXY_STATUS_VERIFIED && ( { - if (buttonIndex === 0) { +const handleAlertResponse = async (buttonIndex: number, serverUrl?: string) => { + 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) { +export function alertPushProxyError(intl: IntlShape, serverUrl?: string) { Alert.alert( intl.formatMessage({ id: 'alert.push_proxy_error.title', From 89fc2e8b997d7602137d98059c07295455bddbc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Wed, 18 Oct 2023 12:12:37 +0200 Subject: [PATCH 06/23] Update alert text --- app/utils/push_proxy.ts | 2 +- assets/base/i18n/en.json | 2 +- assets/base/i18n/en_AU.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index 4dcb3cd3b..332d720e2 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -51,7 +51,7 @@ export function alertPushProxyError(intl: IntlShape, serverUrl?: string) { }), 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'}), diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index eb879a5e3..bd201771e 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 0a8a601d3..3dc5875e4 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", From 6dcc999176e75069dca6332de3a0d8a16a874c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Andr=C3=A9s=20V=C3=A9lez=20Vidal?= Date: Wed, 18 Oct 2023 21:06:12 +0200 Subject: [PATCH 07/23] capitalize back the alert text --- app/utils/push_proxy.ts | 2 +- assets/base/i18n/en.json | 2 +- assets/base/i18n/en_AU.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/utils/push_proxy.ts b/app/utils/push_proxy.ts index 332d720e2..ec84c91c3 100644 --- a/app/utils/push_proxy.ts +++ b/app/utils/push_proxy.ts @@ -51,7 +51,7 @@ export function alertPushProxyError(intl: IntlShape, serverUrl?: string) { }), intl.formatMessage({ id: 'alert.push_proxy_error.description', - defaultMessage: 'due to the configuration of 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'}), diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index bd201771e..9ef4dd764 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 of 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 3dc5875e4..aa9654932 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 of 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", From 12a29fe33e8abed246adbebc4f54576a4b0901f0 Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Thu, 19 Oct 2023 10:34:21 +0400 Subject: [PATCH 08/23] Fix race condition when showing the turorial (#7599) --- app/components/tutorial_highlight/index.tsx | 14 +--- app/components/user_item/user_item.tsx | 3 + .../__snapshots__/index.test.tsx.snap | 80 ++----------------- app/components/user_list_row/index.tsx | 10 ++- .../servers_list/server_item/server_item.tsx | 12 ++- 5 files changed, 28 insertions(+), 91 deletions(-) diff --git a/app/components/tutorial_highlight/index.tsx b/app/components/tutorial_highlight/index.tsx index 182ad6e6e..2be624c19 100644 --- a/app/components/tutorial_highlight/index.tsx +++ b/app/components/tutorial_highlight/index.tsx @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import React, {useCallback} from 'react'; -import {Modal, StyleSheet, useWindowDimensions, View} from 'react-native'; +import {Modal, useWindowDimensions} from 'react-native'; import HighlightItem from './item'; @@ -11,11 +11,10 @@ type Props = { itemBounds: TutorialItemBounds; itemBorderRadius?: number; onDismiss: () => void; - onLayout: () => void; onShow?: () => void; } -const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onLayout, onShow}: Props) => { +const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, onShow}: Props) => { const {width, height} = useWindowDimensions(); const handleShowTutorial = useCallback(() => { @@ -26,19 +25,13 @@ const TutorialHighlight = ({children, itemBounds, itemBorderRadius, onDismiss, o return ( 0} transparent={true} animationType='fade' onDismiss={onDismiss} onRequestClose={onDismiss} testID='tutorial_highlight' > - - {itemBounds.endX > 0 && - } {children} ); diff --git a/app/components/user_item/user_item.tsx b/app/components/user_item/user_item.tsx index 0c2881bb4..a3f4a9e9a 100644 --- a/app/components/user_item/user_item.tsx +++ b/app/components/user_item/user_item.tsx @@ -32,6 +32,7 @@ type Props = { rightDecorator?: React.ReactNode; onUserPress?: (user: UserProfile | UserModel) => void; onUserLongPress?: (user: UserProfile | UserModel) => void; + onLayout?: () => void; disabled?: boolean; viewRef?: React.LegacyRef; padding?: number; @@ -102,6 +103,7 @@ const UserItem = ({ locale, teammateNameDisplay, rightDecorator, + onLayout, onUserPress, onUserLongPress, disabled = false, @@ -159,6 +161,7 @@ const UserItem = ({ onPress={onPress} onLongPress={onLongPress} disabled={!(onUserPress || onUserLongPress)} + onLayout={onLayout} > - - - - - - Long-press on an item to view a user's profile - - - - + visible={false} + /> { - startTutorial(); - }, []); + if (showTutorial) { + startTutorial(); + } + }, [showTutorial]); const icon = useMemo(() => { if (!selectable && !selected) { @@ -190,17 +192,19 @@ function UserListRow({ viewRef={viewRef} padding={20} includeMargin={includeMargin} + onLayout={onLayout} /> {showTutorial && + {Boolean(itemBounds.endX) && + } } diff --git a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx index efe10083e..c078856e4 100644 --- a/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx +++ b/app/screens/home/channel_list/servers/servers_list/server_item/server_item.tsx @@ -213,9 +213,11 @@ const ServerItem = ({ }; const onLayout = useCallback(() => { - swipeable.current?.close(); - startTutorial(); - }, []); + if (showTutorial) { + swipeable.current?.close(); + startTutorial(); + } + }, [showTutorial]); const containerStyle = useMemo(() => { const style: StyleProp = [styles.container]; @@ -390,6 +392,7 @@ const ServerItem = ({ style={containerStyle} ref={viewRef} testID={serverItemTestId} + onLayout={onLayout} > + {Boolean(itemBounds.endX) && + } } From f1e17d2ef180d3059dd25abbacd3f78f77f87c56 Mon Sep 17 00:00:00 2001 From: Amy Blais <29708087+amyblais@users.noreply.github.com> Date: Thu, 19 Oct 2023 08:30:33 -0400 Subject: [PATCH 09/23] Update NOTICE.txt (#7607) --- NOTICE.txt | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/NOTICE.txt b/NOTICE.txt index 7a0630561..11ccab47a 100644 --- a/NOTICE.txt +++ b/NOTICE.txt @@ -667,6 +667,38 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--- + +## @voximplant/react-native-foreground-service + +This product contains a modified version of '@voximplant/react-native-foreground-service' by Voximplant. + +A foreground service performs some operation that is noticeable to the user. + +* HOMEPAGE: + * https://github.com/voximplant/react-native-foreground-service + +* LICENSE: MIT License + +Copyright (c) 2019 Zingaya, Inc + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. --- From cc118c30ebeb26c68e8cfbbbffa2e8094298e9ee Mon Sep 17 00:00:00 2001 From: Tom De Moor Date: Thu, 19 Oct 2023 16:19:53 +0200 Subject: [PATCH 10/23] Removing empy zh_Han* files that are raising an alert in Weblate (#7615) Co-authored-by: Tom De Moor --- assets/base/i18n/zh_Hans.json | 1 - assets/base/i18n/zh_Hant.json | 1 - 2 files changed, 2 deletions(-) delete mode 100644 assets/base/i18n/zh_Hans.json delete mode 100644 assets/base/i18n/zh_Hant.json diff --git a/assets/base/i18n/zh_Hans.json b/assets/base/i18n/zh_Hans.json deleted file mode 100644 index 0967ef424..000000000 --- a/assets/base/i18n/zh_Hans.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/assets/base/i18n/zh_Hant.json b/assets/base/i18n/zh_Hant.json deleted file mode 100644 index 0967ef424..000000000 --- a/assets/base/i18n/zh_Hant.json +++ /dev/null @@ -1 +0,0 @@ -{} From f30384eb22773824584dbd4b628e3a7cc920c16a Mon Sep 17 00:00:00 2001 From: Elias Nahum Date: Fri, 20 Oct 2023 10:55:53 +0400 Subject: [PATCH 11/23] Bump to version 2.10.0 build 490 (#7621) * Bump app version number to 2.10.0 * Bump app build number to 490 --- android/app/build.gradle | 4 ++-- ios/Mattermost.xcodeproj/project.pbxproj | 8 ++++---- ios/Mattermost/Info.plist | 4 ++-- ios/MattermostShare/Info.plist | 4 ++-- ios/NotificationService/Info.plist | 4 ++-- package-lock.json | 5 +++-- package.json | 2 +- 7 files changed, 16 insertions(+), 15 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 349155214..668e84164 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,8 +110,8 @@ android { applicationId "com.mattermost.rnbeta" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 489 - versionName "2.9.0" + versionCode 490 + versionName "2.10.0" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index fe32e093e..8d45db34d 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -1929,7 +1929,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 489; + CURRENT_PROJECT_VERSION = 490; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -1973,7 +1973,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 489; + CURRENT_PROJECT_VERSION = 490; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -2116,7 +2116,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 489; + CURRENT_PROJECT_VERSION = 490; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2165,7 +2165,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 489; + CURRENT_PROJECT_VERSION = 490; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist index 41404b833..27de4b73f 100644 --- a/ios/Mattermost/Info.plist +++ b/ios/Mattermost/Info.plist @@ -21,7 +21,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 2.9.0 + 2.10.0 CFBundleSignature ???? CFBundleURLTypes @@ -37,7 +37,7 @@ CFBundleVersion - 489 + 490 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/ios/MattermostShare/Info.plist b/ios/MattermostShare/Info.plist index 51abcdda1..006552425 100644 --- a/ios/MattermostShare/Info.plist +++ b/ios/MattermostShare/Info.plist @@ -19,9 +19,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 2.9.0 + 2.10.0 CFBundleVersion - 489 + 490 UIAppFonts OpenSans-Bold.ttf diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index bef506837..bbe279808 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -19,9 +19,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 2.9.0 + 2.10.0 CFBundleVersion - 489 + 490 NSExtension NSExtensionPointIdentifier diff --git a/package-lock.json b/package-lock.json index 0f08eb554..aae1845dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "mattermost-mobile", - "version": "2.9.0", + "version": "2.10.0", "lockfileVersion": 2, "requires": true, "packages": { @@ -28521,7 +28521,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@voximplant/react-native-foreground-service/-/react-native-foreground-service-3.0.2.tgz", "integrity": "sha512-ZIyccOAXPqznA1PAVAYlKZ+GI7kXYCuYgH+gmAkhPouyJbkgrSXaCJJzQ+uBkPr4FBa/PuC/yjzK8vf6tJREQA==", - "requires": {} + "requires": { + } }, "@webassemblyjs/ast": { "version": "1.11.1", diff --git a/package.json b/package.json index 00059f2e3..cf6e99745 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mattermost-mobile", - "version": "2.9.0", + "version": "2.10.0", "description": "Mattermost Mobile with React Native", "repository": "git@github.com:mattermost/mattermost-mobile.git", "author": "Mattermost, Inc.", From 1a031cdbbe1a308aa4849cca05ef0afae299e3af Mon Sep 17 00:00:00 2001 From: Harrison Healey Date: Tue, 24 Oct 2023 16:21:14 -0400 Subject: [PATCH 12/23] MM-54887 Fix category order being reversed after moving a channel (#7628) --- app/database/models/server/category.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/database/models/server/category.ts b/app/database/models/server/category.ts index 73b9f87fb..d7247fe22 100644 --- a/app/database/models/server/category.ts +++ b/app/database/models/server/category.ts @@ -120,7 +120,7 @@ export default class CategoryModel extends Model implements CategoryInterface { toCategoryWithChannels = async (): Promise => { const categoryChannels = await this.categoryChannels.fetch(); const orderedChannelIds = categoryChannels.sort((a, b) => { - return b.sortOrder - a.sortOrder; + return a.sortOrder - b.sortOrder; }).map((cc) => cc.channelId); return { From 01fdd1f7d4b0e75f1dfc0961d36c5223d20bc200 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Thu, 26 Oct 2023 15:15:54 +0200 Subject: [PATCH 13/23] Fix recent sorting difference with webapp (#7632) --- app/utils/categories.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/utils/categories.ts b/app/utils/categories.ts index 7b2d3e604..91f9afadc 100644 --- a/app/utils/categories.ts +++ b/app/utils/categories.ts @@ -180,7 +180,9 @@ const sortChannelsByName = (notifyPropsPerChannel: Record>, locale: string) => { if (sorting === 'recent') { return channelsWithMyChannel.sort((cwmA, cwmB) => { - return cwmB.myChannel.lastPostAt - cwmA.myChannel.lastPostAt; + const a = Math.max(cwmA.myChannel.lastPostAt, cwmA.channel.createAt); + const b = Math.max(cwmB.myChannel.lastPostAt, cwmB.channel.createAt); + return b - a; }).map((cwm) => cwm.channel); } else if (sorting === 'manual') { return channelsWithMyChannel.sort((cwmA, cwmB) => { From 2583b470b28a9737fae1b9ee9059a00d5caa5cae Mon Sep 17 00:00:00 2001 From: Paul Vrn <78180340+Paul-vrn@users.noreply.github.com> Date: Mon, 30 Oct 2023 04:53:15 +0100 Subject: [PATCH 14/23] [MM-54599] Fix Servers bottom sheet (#7609) --- app/screens/home/channel_list/servers/index.tsx | 15 +++++++++++---- .../channel_list/servers/servers_list/index.tsx | 7 ++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/app/screens/home/channel_list/servers/index.tsx b/app/screens/home/channel_list/servers/index.tsx index a1135ce4f..307c9a5af 100644 --- a/app/screens/home/channel_list/servers/index.tsx +++ b/app/screens/home/channel_list/servers/index.tsx @@ -3,7 +3,7 @@ import React, {useCallback, useEffect, useImperativeHandle, useRef, useState} from 'react'; import {useIntl} from 'react-intl'; -import {StyleSheet} from 'react-native'; +import {Dimensions, StyleSheet} from 'react-native'; import {useSafeAreaInsets} from 'react-native-safe-area-context'; import ServerIcon from '@components/server_icon'; @@ -27,7 +27,8 @@ export type ServersRef = { openServers: () => void; } -export const SERVER_ITEM_HEIGHT = 72; +export const SERVER_ITEM_HEIGHT = 75; +export const PUSH_ALERT_TEXT_HEIGHT = 42; const subscriptions: Map = new Map(); const styles = StyleSheet.create({ @@ -116,12 +117,18 @@ const Servers = React.forwardRef((_, ref) => { ); }; + const maxScreenHeight = Math.ceil(0.6 * Dimensions.get('window').height); + const maxSnapPoint = Math.min( + maxScreenHeight, + bottomSheetSnapPoint(registeredServers.current.length, SERVER_ITEM_HEIGHT, bottom) + TITLE_HEIGHT + BUTTON_HEIGHT + + (registeredServers.current.filter((s: ServersModel) => s.lastActiveAt).length * PUSH_ALERT_TEXT_HEIGHT), + ); const snapPoints: BottomSheetProps['snapPoints'] = [ 1, - bottomSheetSnapPoint(Math.min(2.5, registeredServers.current.length), 72, bottom) + TITLE_HEIGHT + BUTTON_HEIGHT, + maxSnapPoint, ]; - if (registeredServers.current.length > 1) { + if (maxSnapPoint === maxScreenHeight) { snapPoints.push('80%'); } diff --git a/app/screens/home/channel_list/servers/servers_list/index.tsx b/app/screens/home/channel_list/servers/servers_list/index.tsx index 22cac4f22..ead1bf96d 100644 --- a/app/screens/home/channel_list/servers/servers_list/index.tsx +++ b/app/screens/home/channel_list/servers/servers_list/index.tsx @@ -4,11 +4,12 @@ import {BottomSheetFlatList} from '@gorhom/bottom-sheet'; import React, {useCallback, useMemo} from 'react'; import {useIntl} from 'react-intl'; -import {FlatList, type ListRenderItemInfo, StyleSheet, View} from 'react-native'; +import {FlatList, StyleSheet, View, type ListRenderItemInfo} from 'react-native'; import {useServerUrl} from '@context/server'; import {useTheme} from '@context/theme'; import {useIsTablet} from '@hooks/device'; +import {BUTTON_HEIGHT} from '@screens/bottom_sheet'; import BottomSheetContent from '@screens/bottom_sheet/content'; import {addNewServer} from '@utils/server'; @@ -29,6 +30,9 @@ const styles = StyleSheet.create({ contentContainer: { marginVertical: 4, }, + serverList: { + marginBottom: BUTTON_HEIGHT, + }, }); const keyExtractor = (item: ServersModel) => item.url; @@ -68,6 +72,7 @@ const ServerList = ({servers}: Props) => { Date: Mon, 30 Oct 2023 09:46:49 +0100 Subject: [PATCH 15/23] Fix notifications not opening or going to the wrong channel on Android (#7634) * Fix notifications not opening or going to the wrong channel on Android * Update podfile --- ios/Podfile.lock | 6 +- package-lock.json | 166 ++++++------------ package.json | 2 +- ...=> react-native-notifications+5.1.0.patch} | 18 +- 4 files changed, 72 insertions(+), 120 deletions(-) rename patches/{react-native-notifications+5.0.0.patch => react-native-notifications+5.1.0.patch} (97%) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 3b04b7c0a..69a4e3a57 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -385,7 +385,7 @@ PODS: - React-Core - Starscream (~> 4.0.4) - SwiftyJSON (~> 5.0) - - react-native-notifications (5.0.0): + - react-native-notifications (5.1.0): - React-Core - react-native-paste-input (0.6.4): - React-Core @@ -946,7 +946,7 @@ SPEC CHECKSUMS: react-native-in-app-review: db8bb167a5f238e7ceca5c242d6b36ce8c4404a4 react-native-netinfo: fefd4e98d75cbdd6e85fc530f7111a8afdf2b0c5 react-native-network-client: 953ab4d0914fdde6dc40924b5faad8631a587d4e - react-native-notifications: d309f7080aad71206882dbb98d9ed788969f3b6d + react-native-notifications: 4601a5a8db4ced6ae7cfc43b44d35fe437ac50c4 react-native-paste-input: 09f14cbfb646ad9d2ef79cdc6f3d45f337c10ad1 react-native-safe-area-context: 9697629f7b2cda43cf52169bb7e0767d330648c2 react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 @@ -1001,4 +1001,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 25f07cb9e5eed8c84db8e8723000e8470c349058 -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.2 diff --git a/package-lock.json b/package-lock.json index aae1845dd..2283bdf25 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "mattermost-mobile", - "version": "2.9.0", + "version": "2.10.0", "hasInstallScript": true, "license": "Apache 2.0", "dependencies": { @@ -82,7 +82,7 @@ "react-native-localize": "3.0.2", "react-native-math-view": "3.9.5", "react-native-navigation": "7.37.0", - "react-native-notifications": "5.0.0", + "react-native-notifications": "5.1.0", "react-native-permissions": "3.8.4", "react-native-reanimated": "3.4.2", "react-native-safe-area-context": "4.7.1", @@ -19506,9 +19506,9 @@ "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" }, "node_modules/react-native-notifications": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-5.0.0.tgz", - "integrity": "sha512-QXtBBmbDtwq9X8WAPLn+OctIeEtnJOQ+RCT6iweaypvFTydt2baLPtawTAbCSXKuWpVDqDAdmZnlQjCcavNzoA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-5.1.0.tgz", + "integrity": "sha512-laqDSDlCvEASmJR6cXpqaryK855ejQd07vrfYERzhv68YDOoSkKy/URExRP4vAfAOVqHhix80tLbNUcfvZk2VQ==", "peerDependencies": { "react": "*", "react-native": "*" @@ -23596,8 +23596,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "requires": { - } + "requires": {} }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -25420,8 +25419,7 @@ "version": "1.3.5", "resolved": "https://registry.npmjs.org/@mattermost/react-native-emm/-/react-native-emm-1.3.5.tgz", "integrity": "sha512-REdUEsm/RA6lI1Rt4b009jvWn28f7H+e27gd4hlNk6zesIh/dlfiHwYfInW/vwbNFBdSPpvHy7Qi2mdcvrNqhg==", - "requires": { - } + "requires": {} }, "@mattermost/react-native-network-client": { "version": "1.4.1", @@ -25444,8 +25442,7 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@mattermost/react-native-turbo-log/-/react-native-turbo-log-0.2.3.tgz", "integrity": "sha512-usWyD8zVAHzrYqgPH1ne5I14gCOkhS2mefK58g5v4DewZfCm0/Uc0w8MRuPS/9jyOPPq1rUZj8U1AqKgEne9tQ==", - "requires": { - } + "requires": {} }, "@msgpack/msgpack": { "version": "2.8.0", @@ -25537,15 +25534,13 @@ "version": "5.7.2", "resolved": "https://registry.npmjs.org/@react-native-camera-roll/camera-roll/-/camera-roll-5.7.2.tgz", "integrity": "sha512-s8VAUG1Kvi+tEJkLHObmOJdXAL/uclnXJ/IdnJtx2fCKiWA3Ho0ln9gDQqCYHHHHu+sXk7wovsH/I2/AYy0brg==", - "requires": { - } + "requires": {} }, "@react-native-clipboard/clipboard": { "version": "1.11.2", "resolved": "https://registry.npmjs.org/@react-native-clipboard/clipboard/-/clipboard-1.11.2.tgz", "integrity": "sha512-bHyZVW62TuleiZsXNHS1Pv16fWc0fh8O9WvBzl4h2fykqZRW9a+Pv/RGTH56E3X2PqzHP38K5go8zmCZUoIsoQ==", - "requires": { - } + "requires": {} }, "@react-native-community/cli": { "version": "10.2.4", @@ -27254,8 +27249,7 @@ "version": "9.4.1", "resolved": "https://registry.npmjs.org/@react-native-community/netinfo/-/netinfo-9.4.1.tgz", "integrity": "sha512-dAbY5mfw+6Kas/GJ6QX9AZyY+K+eq9ad4Su6utoph/nxyH3whp5cMSgRNgE2VhGQVRZ/OG0qq3IaD3+wzoqJXw==", - "requires": { - } + "requires": {} }, "@react-native-cookies/cookies": { "version": "6.2.1", @@ -27421,8 +27415,7 @@ "version": "1.3.18", "resolved": "https://registry.npmjs.org/@react-navigation/elements/-/elements-1.3.18.tgz", "integrity": "sha512-/0hwnJkrr415yP0Hf4PjUKgGyfshrvNUKFXN85Mrt1gY49hy9IwxZgrrxlh0THXkPeq8q4VWw44eHDfAcQf20Q==", - "requires": { - } + "requires": {} }, "@react-navigation/native": { "version": "6.1.7", @@ -27649,72 +27642,63 @@ "version": "0.10.3", "resolved": "https://registry.npmjs.org/@stream-io/flat-list-mvcp/-/flat-list-mvcp-0.10.3.tgz", "integrity": "sha512-2ZK8piYlEfKIPZrH8BpZz9uj8HZcUvMCV0X7qSLSAc/vhLOANBfR0SSn0OaWPbqb2mFGAd4FxmLSPp1zKEYuaw==", - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-add-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-add-jsx-attribute/-/babel-plugin-add-jsx-attribute-8.0.0.tgz", "integrity": "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-remove-jsx-attribute": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-attribute/-/babel-plugin-remove-jsx-attribute-8.0.0.tgz", "integrity": "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-remove-jsx-empty-expression": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-remove-jsx-empty-expression/-/babel-plugin-remove-jsx-empty-expression-8.0.0.tgz", "integrity": "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-replace-jsx-attribute-value": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-replace-jsx-attribute-value/-/babel-plugin-replace-jsx-attribute-value-8.0.0.tgz", "integrity": "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-svg-dynamic-title": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-dynamic-title/-/babel-plugin-svg-dynamic-title-8.0.0.tgz", "integrity": "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-svg-em-dimensions": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-svg-em-dimensions/-/babel-plugin-svg-em-dimensions-8.0.0.tgz", "integrity": "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-transform-react-native-svg": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-react-native-svg/-/babel-plugin-transform-react-native-svg-8.0.0.tgz", "integrity": "sha512-UKrY3860AQICgH7g+6h2zkoxeVEPLYwX/uAjmqo4PIq2FIHppwhIqZstIyTz0ZtlwreKR41O3W3BzsBBiJV2Aw==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-plugin-transform-svg-component": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/@svgr/babel-plugin-transform-svg-component/-/babel-plugin-transform-svg-component-8.0.0.tgz", "integrity": "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==", "dev": true, - "requires": { - } + "requires": {} }, "@svgr/babel-preset": { "version": "8.0.0", @@ -28521,8 +28505,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@voximplant/react-native-foreground-service/-/react-native-foreground-service-3.0.2.tgz", "integrity": "sha512-ZIyccOAXPqznA1PAVAYlKZ+GI7kXYCuYgH+gmAkhPouyJbkgrSXaCJJzQ+uBkPr4FBa/PuC/yjzK8vf6tJREQA==", - "requires": { - } + "requires": {} }, "@webassemblyjs/ast": { "version": "1.11.1", @@ -28690,8 +28673,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz", "integrity": "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==", "dev": true, - "requires": { - } + "requires": {} }, "@webpack-cli/info": { "version": "1.4.0", @@ -28707,8 +28689,7 @@ "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz", "integrity": "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==", "dev": true, - "requires": { - } + "requires": {} }, "@xtuc/ieee754": { "version": "1.2.0", @@ -28763,15 +28744,13 @@ "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", "dev": true, "peer": true, - "requires": { - } + "requires": {} }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "requires": { - } + "requires": {} }, "agent-base": { "version": "6.0.2", @@ -28827,8 +28806,7 @@ "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, "peer": true, - "requires": { - } + "requires": {} }, "anser": { "version": "1.4.10", @@ -29106,8 +29084,7 @@ "version": "7.0.0-bridge.0", "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", - "requires": { - } + "requires": {} }, "babel-jest": { "version": "29.6.2", @@ -30308,8 +30285,7 @@ "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", "dev": true, - "requires": { - } + "requires": {} }, "deep-equal": { "version": "2.2.2", @@ -31212,8 +31188,7 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", - "requires": { - } + "requires": {} }, "eslint-import-resolver-node": { "version": "0.3.7", @@ -31298,8 +31273,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==", "dev": true, - "requires": { - } + "requires": {} }, "eslint-plugin-import": { "version": "2.28.0", @@ -31433,8 +31407,7 @@ "version": "4.6.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", - "requires": { - } + "requires": {} }, "eslint-plugin-react-native": { "version": "4.0.0", @@ -33808,8 +33781,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "requires": { - } + "requires": {} }, "jest-regex-util": { "version": "29.4.3", @@ -37037,8 +37009,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/react-freeze/-/react-freeze-1.0.3.tgz", "integrity": "sha512-ZnXwLQnGzrDpHBHiC56TXFXvmolPeMjTn1UOm610M4EXGzbEDR7oOIyS2ZiItgbs6eZc4oU/a0hpk8PrcKvv5g==", - "requires": { - } + "requires": {} }, "react-intl": { "version": "6.4.4", @@ -37347,8 +37318,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/react-native-background-timer/-/react-native-background-timer-2.4.1.tgz", "integrity": "sha512-TE4Kiy7jUyv+hugxDxitzu38sW1NqjCk4uE5IgU2WevLv7sZacaBc6PZKOShNRPGirLl1NWkaG3LDEkdb9Um5g==", - "requires": { - } + "requires": {} }, "react-native-button": { "version": "3.1.0", @@ -37401,15 +37371,13 @@ "version": "1.6.4", "resolved": "https://registry.npmjs.org/react-native-create-thumbnail/-/react-native-create-thumbnail-1.6.4.tgz", "integrity": "sha512-JWuKXswDXtqUPfuqh6rjCVMvTSSG3kUtwvSK/YdaNU0i+nZKxeqHmt/CO2+TyI/WSUFynGVmWT1xOHhCZAFsRQ==", - "requires": { - } + "requires": {} }, "react-native-device-info": { "version": "10.8.0", "resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-10.8.0.tgz", "integrity": "sha512-DE4/X82ZVhdcnR1Y21iTP46WSSJA/rHK3lmeqWfGGq1RKLwXTIdxmfbZZnYwryqJ+esrw2l4ND19qlgxDGby8A==", - "requires": { - } + "requires": {} }, "react-native-document-picker": { "version": "9.0.1", @@ -37446,22 +37414,19 @@ "version": "2.10.10", "resolved": "https://registry.npmjs.org/react-native-exception-handler/-/react-native-exception-handler-2.10.10.tgz", "integrity": "sha512-otAXGoZDl1689OoUJWN/rXxVbdoZ3xcmyF1uq/CsizdLwwyZqVGd6d+p/vbYvnF996FfEyAEBnHrdFxulTn51w==", - "requires": { - } + "requires": {} }, "react-native-fast-image": { "version": "8.6.3", "resolved": "https://registry.npmjs.org/react-native-fast-image/-/react-native-fast-image-8.6.3.tgz", "integrity": "sha512-Sdw4ESidXCXOmQ9EcYguNY2swyoWmx53kym2zRsvi+VeFCHEdkO+WG1DK+6W81juot40bbfLNhkc63QnWtesNg==", - "requires": { - } + "requires": {} }, "react-native-file-viewer": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/react-native-file-viewer/-/react-native-file-viewer-2.1.5.tgz", "integrity": "sha512-MGC6sx9jsqHdefhVQ6o0akdsPGpkXgiIbpygb2Sg4g4bh7v6K1cardLV1NwGB9A6u1yICOSDT/MOC//9Ez6EUg==", - "requires": { - } + "requires": {} }, "react-native-fs": { "version": "2.20.0", @@ -37500,22 +37465,19 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/react-native-haptic-feedback/-/react-native-haptic-feedback-2.0.3.tgz", "integrity": "sha512-7+qvcxXZts/hA+HOOIFyM1x9m9fn/TJVSTgXaoQ8uT4gLc97IMvqHQ559tDmnlth+hHMzd3HRMpmRLWoKPL0DA==", - "requires": { - } + "requires": {} }, "react-native-hw-keyboard-event": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/react-native-hw-keyboard-event/-/react-native-hw-keyboard-event-0.0.4.tgz", "integrity": "sha512-G8qp0nm17PHigLb/axgdF9xg51BKCG2p1AGeq//J/luLp5zNczIcQJh+nm02R1MeEUE3e53wqO4LMe0MV3raZg==", - "requires": { - } + "requires": {} }, "react-native-image-picker": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/react-native-image-picker/-/react-native-image-picker-5.6.1.tgz", "integrity": "sha512-LPPlgJi97EzCDY4NWp7z0oUWmCbagnB6HSoKcLJHJD/DaFYN/dJPrqjqKaqqw8K/5Ze6DIsNg9PZohjNEYQQWQ==", - "requires": { - } + "requires": {} }, "react-native-in-app-review": { "version": "4.3.3", @@ -37526,15 +37488,13 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/react-native-incall-manager/-/react-native-incall-manager-4.1.0.tgz", "integrity": "sha512-v1c+XOGu5VudY5//E3i5xiaRA9v6RvevMzZ4RumLqI+hte+4XslB2z6HSek2FF0EmAnY1rCn4ckiwgkTI1Tmtw==", - "requires": { - } + "requires": {} }, "react-native-iphone-x-helper": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/react-native-iphone-x-helper/-/react-native-iphone-x-helper-1.3.1.tgz", "integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==", - "requires": { - } + "requires": {} }, "react-native-keyboard-aware-scroll-view": { "version": "0.9.5", @@ -37549,8 +37509,7 @@ "version": "5.7.0", "resolved": "https://registry.npmjs.org/react-native-keyboard-tracking-view/-/react-native-keyboard-tracking-view-5.7.0.tgz", "integrity": "sha512-MDeEwAbn9LJDOfHq0QLCGaZirVLk2X/tHqkAqz3y6uxryTRdSl9PwleOVar5Jx2oAPEg4J9BXbUD1wwOOi+5Kg==", - "requires": { - } + "requires": {} }, "react-native-keychain": { "version": "8.1.2", @@ -37561,15 +37520,13 @@ "version": "2.8.2", "resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.8.2.tgz", "integrity": "sha512-hgmCsgzd58WNcDCyPtKrvxsaoETjb/jLGxis/dmU3Aqm2u4ICIduj4ECjbil7B7pm9OnuTkmpwXu08XV2mpg8g==", - "requires": { - } + "requires": {} }, "react-native-localize": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/react-native-localize/-/react-native-localize-3.0.2.tgz", "integrity": "sha512-/l/oE1LVNgIRRhLbhmfFMHiWV0xhUn0A0iz1ytLVRYywL7FTp8Rx2vkJS/q/RpExDvV7yLw2493XZBYIM1dnLQ==", - "requires": { - } + "requires": {} }, "react-native-math-view": { "version": "3.9.5", @@ -37602,11 +37559,10 @@ } }, "react-native-notifications": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-5.0.0.tgz", - "integrity": "sha512-QXtBBmbDtwq9X8WAPLn+OctIeEtnJOQ+RCT6iweaypvFTydt2baLPtawTAbCSXKuWpVDqDAdmZnlQjCcavNzoA==", - "requires": { - } + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-native-notifications/-/react-native-notifications-5.1.0.tgz", + "integrity": "sha512-laqDSDlCvEASmJR6cXpqaryK855ejQd07vrfYERzhv68YDOoSkKy/URExRP4vAfAOVqHhix80tLbNUcfvZk2VQ==", + "requires": {} }, "react-native-permissions": { "version": "3.8.4", @@ -37647,8 +37603,7 @@ "version": "4.7.1", "resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.7.1.tgz", "integrity": "sha512-X2pJG2ttmAbiGlItWedvDkZg1T1ikmEDiz+7HsiIwAIm2UbFqlhqn+B1JF53mSxPzdNaDcCQVHRNPvj8oFu6Yg==", - "requires": { - } + "requires": {} }, "react-native-screens": { "version": "3.24.0", @@ -37681,8 +37636,7 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/react-native-size-matters/-/react-native-size-matters-0.3.1.tgz", "integrity": "sha512-mKOfBLIBFBcs9br1rlZDvxD5+mAl8Gfr5CounwJtxI6Z82rGrMO+Kgl9EIg3RMVf3G855a85YVqHJL2f5EDRlw==", - "requires": { - } + "requires": {} }, "react-native-svg": { "version": "13.11.0", @@ -39356,8 +39310,7 @@ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", "dev": true, - "requires": { - } + "requires": {} }, "ts-jest": { "version": "29.1.1", @@ -39678,15 +39631,13 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.1.6.tgz", "integrity": "sha512-VO/P91A/PmKH9bcN9a7O3duSuxe6M14ZoYXgA6a8dab8doWNdhiIHzEkX/jFeTTRBsX0Ubk6nG4q2NIjNsj+bg==", - "requires": { - } + "requires": {} }, "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": { - } + "requires": {} }, "utf8": { "version": "3.0.0", @@ -40019,8 +39970,7 @@ "version": "7.5.5", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", - "requires": { - } + "requires": {} }, "xdate": { "version": "0.8.2", diff --git a/package.json b/package.json index cf6e99745..14ce54531 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "react-native-localize": "3.0.2", "react-native-math-view": "3.9.5", "react-native-navigation": "7.37.0", - "react-native-notifications": "5.0.0", + "react-native-notifications": "5.1.0", "react-native-permissions": "3.8.4", "react-native-reanimated": "3.4.2", "react-native-safe-area-context": "4.7.1", diff --git a/patches/react-native-notifications+5.0.0.patch b/patches/react-native-notifications+5.1.0.patch similarity index 97% rename from patches/react-native-notifications+5.0.0.patch rename to patches/react-native-notifications+5.1.0.patch index e652f3263..dcb96e769 100644 --- a/patches/react-native-notifications+5.0.0.patch +++ b/patches/react-native-notifications+5.1.0.patch @@ -1,5 +1,5 @@ diff --git a/node_modules/react-native-notifications/lib/android/app/build.gradle b/node_modules/react-native-notifications/lib/android/app/build.gradle -index d049e84..9ad7004 100644 +index 30bb01c..bba788d 100644 --- a/node_modules/react-native-notifications/lib/android/app/build.gradle +++ b/node_modules/react-native-notifications/lib/android/app/build.gradle @@ -96,9 +96,9 @@ android { @@ -7,10 +7,10 @@ index d049e84..9ad7004 100644 testOptions { unitTests.all { t -> - reports { -- html.enabled true +- html.required.set true - } + // reports { -+ // html.enabled true ++ // html.required.set true + // } testLogging { events "PASSED", "SKIPPED", "FAILED", "standardOut", "standardError" @@ -90,10 +90,10 @@ index 5b7f15f..9381794 100644 } } diff --git a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java -index 1e7e871..62e5cb8 100644 +index 1e7e871..36b96b6 100644 --- a/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java +++ b/node_modules/react-native-notifications/lib/android/app/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java -@@ -14,17 +14,9 @@ public class NotificationIntentAdapter { +@@ -14,17 +14,11 @@ public class NotificationIntentAdapter { @SuppressLint("UnspecifiedImmutableFlag") public static PendingIntent createPendingNotificationIntent(Context appContext, PushNotificationProps notification) { @@ -108,9 +108,11 @@ index 1e7e871..62e5cb8 100644 - taskStackBuilder.addNextIntentWithParentStack(mainActivityIntent); - return taskStackBuilder.getPendingIntent((int) System.currentTimeMillis(), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); - } -+ Intent intent = appContext.getPackageManager().getLaunchIntentForPackage(appContext.getPackageName()); -+ intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle()); -+ return PendingIntent.getActivity(appContext, (int) System.currentTimeMillis(), intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); ++ Intent mainActivityIntent = appContext.getPackageManager().getLaunchIntentForPackage(appContext.getPackageName()); ++ mainActivityIntent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle()); ++ TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(appContext); ++ taskStackBuilder.addNextIntentWithParentStack(mainActivityIntent); ++ return taskStackBuilder.getPendingIntent((int) System.currentTimeMillis(), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE); } public static boolean canHandleTrampolineActivity(Context appContext) { From d8d607257f557c17aaad3d756f100cc24839629e Mon Sep 17 00:00:00 2001 From: Tanmay Vardhaman Thole <72058456+tanmaythole@users.noreply.github.com> Date: Mon, 30 Oct 2023 16:43:52 +0530 Subject: [PATCH 16/23] copy header text in channel info implemented (#7605) * copy header text in channel info implemented * changes fixed --- app/components/markdown/markdown.tsx | 8 +- .../markdown/markdown_link/markdown_link.tsx | 10 +- app/screens/channel_info/extra/extra.tsx | 144 +++++++++++++++--- assets/base/i18n/en.json | 1 + 4 files changed, 139 insertions(+), 24 deletions(-) diff --git a/app/components/markdown/markdown.tsx b/app/components/markdown/markdown.tsx index f16237245..36bcd7f04 100644 --- a/app/components/markdown/markdown.tsx +++ b/app/components/markdown/markdown.tsx @@ -71,6 +71,7 @@ type MarkdownProps = { textStyles?: MarkdownTextStyles; theme: Theme; value?: string; + onLinkLongPress?: (url?: string) => void; } const getStyleSheet = makeStyleSheetFromTheme((theme) => { @@ -133,7 +134,7 @@ const Markdown = ({ enableInlineLatex, enableLatex, maxNodes, imagesMetadata, isEdited, isReplyPost, isSearchResult, layoutHeight, layoutWidth, location, mentionKeys, minimumHashtagLength = 3, onPostPress, postId, searchPatterns, - textStyles = {}, theme, value = '', baseParagraphStyle, + textStyles = {}, theme, value = '', baseParagraphStyle, onLinkLongPress, }: MarkdownProps) => { const style = getStyleSheet(theme); const managedConfig = useManagedConfig(); @@ -402,7 +403,10 @@ const Markdown = ({ const renderLink = ({children, href}: {children: ReactElement; href: string}) => { return ( - + {children} ); diff --git a/app/components/markdown/markdown_link/markdown_link.tsx b/app/components/markdown/markdown_link/markdown_link.tsx index 64dee57b8..4cc662260 100644 --- a/app/components/markdown/markdown_link/markdown_link.tsx +++ b/app/components/markdown/markdown_link/markdown_link.tsx @@ -23,6 +23,7 @@ type MarkdownLinkProps = { experimentalNormalizeMarkdownLinks: string; href: string; siteURL: string; + onLinkLongPress?: (url?: string) => void; } const style = StyleSheet.create({ @@ -44,7 +45,7 @@ const parseLinkLiteral = (literal: string) => { return parsed.href; }; -const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteURL}: MarkdownLinkProps) => { +const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteURL, onLinkLongPress}: MarkdownLinkProps) => { const intl = useIntl(); const {bottom} = useSafeAreaInsets(); const managedConfig = useManagedConfig(); @@ -109,6 +110,11 @@ const MarkdownLink = ({children, experimentalNormalizeMarkdownLinks, href, siteU const handleLongPress = useCallback(() => { if (managedConfig?.copyAndPasteProtection !== 'true') { + if (onLinkLongPress) { + onLinkLongPress(href); + return; + } + const renderContent = () => { return ( ({ }, })); +const style = StyleSheet.create({ + bottomSheet: { + flex: 1, + }, +}); + +const headerTestId = 'channel_info.extra.header'; + +const onCopy = async (text: string, isLink?: boolean) => { + Clipboard.setString(text); + await dismissBottomSheet(); + if ((Platform.OS === OS_VERSION.ANDROID && Number(Platform.Version) < ANDROID_33) || Platform.OS === OS_VERSION.IOS) { + showSnackBar({ + barType: isLink ? SNACK_BAR_TYPE.LINK_COPIED : SNACK_BAR_TYPE.TEXT_COPIED, + }); + } +}; + const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomStatusEnabled}: Props) => { + const intl = useIntl(); + const {bottom} = useSafeAreaInsets(); const theme = useTheme(); + const managedConfig = useManagedConfig(); + const styles = getStyleSheet(theme); const blockStyles = getMarkdownBlockStyles(theme); const textStyles = getMarkdownTextStyles(theme); @@ -81,6 +114,70 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomS ), }), [createdAt, createdBy, theme]); + const handleLongPress = useCallback((url?: string) => { + if (managedConfig?.copyAndPasteProtection !== 'true') { + const renderContent = () => ( + + { + onCopy(header!); + }} + testID={`${headerTestId}.bottom_sheet.copy_header_text`} + text={intl.formatMessage({ + id: 'mobile.markdown.copy_header', + defaultMessage: 'Copy header text', + })} + /> + {Boolean(url) && ( + { + onCopy(url!, true); + }} + testID={`${headerTestId}.bottom_sheet.copy_url`} + text={intl.formatMessage({ + id: 'mobile.markdown.link.copy_url', + defaultMessage: 'Copy URL', + })} + /> + )} + { + dismissBottomSheet(); + }} + testID={`${headerTestId}.bottom_sheet.cancel`} + text={intl.formatMessage({ + id: 'mobile.post.cancel', + defaultMessage: 'Cancel', + })} + /> + + ); + + bottomSheet({ + closeButtonId: 'close-markdown-link', + renderContent, + snapPoints: [1, bottomSheetSnapPoint(url ? 3 : 2, ITEM_HEIGHT, bottom)], + title: intl.formatMessage({id: 'post.options.title', defaultMessage: 'Options'}), + theme, + }); + } + }, [ + header, + bottom, + theme, + intl.formatMessage, + managedConfig?.copyAndPasteProtection, + ]); + + const touchableHandleLongPress = useCallback(() => handleLongPress(), [handleLongPress]); + return ( {isCustomStatusEnabled && Boolean(customStatus) && @@ -131,25 +228,32 @@ const Extra = ({channelId, createdAt, createdBy, customStatus, header, isCustomS id='channel_info.header' defaultMessage='Header:' style={styles.extraHeading} - testID='channel_info.extra.header' - /> - + + + } {Boolean(createdAt && createdBy) && diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 0f93b5a28..1e4606926 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -613,6 +613,7 @@ "mobile.managed.settings": "Go to settings", "mobile.markdown.code.copy_code": "Copy Code", "mobile.markdown.code.plusMoreLines": "+{count, number} more {count, plural, one {line} other {lines}}", + "mobile.markdown.copy_header": "Copy header text", "mobile.markdown.image.too_large": "Image exceeds max dimensions of {maxWidth} by {maxHeight}:", "mobile.markdown.link.copy_url": "Copy URL", "mobile.mention.copy_mention": "Copy Mention", From 128be0994e80037645ad940211a6d66ff169aada Mon Sep 17 00:00:00 2001 From: Harshal sanghvi Date: Mon, 30 Oct 2023 18:47:00 +0530 Subject: [PATCH 17/23] fixed theme save on android back button (#7579) --- .../settings/display_theme/display_theme.tsx | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/app/screens/settings/display_theme/display_theme.tsx b/app/screens/settings/display_theme/display_theme.tsx index 19c544c3a..76ae88368 100644 --- a/app/screens/settings/display_theme/display_theme.tsx +++ b/app/screens/settings/display_theme/display_theme.tsx @@ -1,7 +1,7 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useCallback, useMemo} from 'react'; +import React, {useCallback, useMemo, useState, useEffect} from 'react'; import {savePreference} from '@actions/remote/preference'; import SettingContainer from '@components/settings/container'; @@ -26,17 +26,22 @@ const DisplayTheme = ({allowedThemeKeys, componentId, currentTeamId, currentUser const serverUrl = useServerUrl(); const theme = useTheme(); const initialTheme = useMemo(() => theme, [/* dependency array should remain empty */]); + const [newTheme, setNewTheme] = useState(undefined); const close = () => popTopScreen(componentId); - const setThemePreference = useCallback((newTheme?: string) => { - const allowedTheme = allowedThemeKeys.find((tk) => tk === newTheme); + useEffect(() => { const differentTheme = theme.type?.toLowerCase() !== newTheme?.toLowerCase(); if (!differentTheme) { close(); return; } + setThemePreference(); + }, [newTheme]); + + const setThemePreference = useCallback(() => { + const allowedTheme = allowedThemeKeys.find((tk) => tk === newTheme); const themeJson = Preferences.THEMES[allowedTheme as ThemeKey] || initialTheme; @@ -47,15 +52,20 @@ const DisplayTheme = ({allowedThemeKeys, componentId, currentTeamId, currentUser value: JSON.stringify(themeJson), }; savePreference(serverUrl, [pref]); - }, [allowedThemeKeys, currentTeamId, theme.type, serverUrl]); + }, [allowedThemeKeys, currentTeamId, theme.type, serverUrl, newTheme]); - useAndroidHardwareBackHandler(componentId, setThemePreference); + const onAndroidBack = () => { + setThemePreference(); + close(); + }; + + useAndroidHardwareBackHandler(componentId, onAndroidBack); return ( {initialTheme.type === 'custom' && ( From 10a58011d4ac3f2631772996b02a9d268618e5c0 Mon Sep 17 00:00:00 2001 From: harshil Sharma Date: Mon, 30 Oct 2023 20:18:06 +0530 Subject: [PATCH 18/23] Fixed bug where icons were missing in plus menu --- .../categories_list/header/plus_menu/item.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx b/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx index 34c61a2a3..f1455daf6 100644 --- a/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx +++ b/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx @@ -16,24 +16,24 @@ const PlusMenuItem = ({pickerAction, onPress}: PlusMenuItemProps) => { const menuItems = { browseChannels: { - icon: 'globe', + leftIcon: 'globe', text: intl.formatMessage({id: 'plus_menu.browse_channels.title', defaultMessage: 'Browse Channels'}), testID: 'plus_menu_item.browse_channels', }, createNewChannel: { - icon: 'plus', + leftIcon: 'plus', text: intl.formatMessage({id: 'plus_menu.create_new_channel.title', defaultMessage: 'Create New Channel'}), testID: 'plus_menu_item.create_new_channel', }, openDirectMessage: { - icon: 'account-outline', + leftIcon: 'account-outline', text: intl.formatMessage({id: 'plus_menu.open_direct_message.title', defaultMessage: 'Open a Direct Message'}), testID: 'plus_menu_item.open_direct_message', }, invitePeopleToTeam: { - icon: 'account-plus-outline', + leftIcon: 'account-plus-outline', text: intl.formatMessage({id: 'plus_menu.invite_people_to_team.title', defaultMessage: 'Invite people to the team'}), testID: 'plus_menu_item.invite_people_to_team', }, From ead1a2f73b87a8ba515e1852360d4e14e18504fa Mon Sep 17 00:00:00 2001 From: harshil Sharma Date: Tue, 31 Oct 2023 07:24:34 +0530 Subject: [PATCH 19/23] added types --- .../home/channel_list/categories_list/header/plus_menu/item.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx b/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx index f1455daf6..5a73b923b 100644 --- a/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx +++ b/app/screens/home/channel_list/categories_list/header/plus_menu/item.tsx @@ -14,7 +14,7 @@ type PlusMenuItemProps = { const PlusMenuItem = ({pickerAction, onPress}: PlusMenuItemProps) => { const intl = useIntl(); - const menuItems = { + const menuItems: {[key: string]: Omit, 'onPress'>} = { browseChannels: { leftIcon: 'globe', text: intl.formatMessage({id: 'plus_menu.browse_channels.title', defaultMessage: 'Browse Channels'}), From b9024f51839bba52598709a7ad91021ef34322f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Tue, 31 Oct 2023 15:59:54 +0100 Subject: [PATCH 20/23] Fix error around combined user activity (#7637) --- .../combined_user_activity.tsx | 38 +++++++++++-------- .../post_list/combined_user_activity/index.ts | 27 +++++++------ 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/app/components/post_list/combined_user_activity/combined_user_activity.tsx b/app/components/post_list/combined_user_activity/combined_user_activity.tsx index f29225ba0..845688c04 100644 --- a/app/components/post_list/combined_user_activity/combined_user_activity.tsx +++ b/app/components/post_list/combined_user_activity/combined_user_activity.tsx @@ -25,7 +25,7 @@ type Props = { currentUserId?: string; currentUsername?: string; location: string; - post: Post; + post: Post | null; showJoinLeave: boolean; testID?: string; theme: Theme; @@ -65,23 +65,11 @@ const CombinedUserActivity = ({ const intl = useIntl(); const isTablet = useIsTablet(); const serverUrl = useServerUrl(); - const itemTestID = `${testID}.${post.id}`; const textStyles = getMarkdownTextStyles(theme); - const {allUserIds, allUsernames, messageData} = post.props.user_activity; const styles = getStyleSheet(theme); const content = []; const removedUserIds: string[] = []; - const loadUserProfiles = () => { - if (allUserIds.length) { - fetchMissingProfilesByIds(serverUrl, allUserIds); - } - - if (allUsernames.length) { - fetchMissingProfilesByUsernames(serverUrl, allUsernames); - } - }; - const getUsernames = (userIds: string[]) => { const someone = intl.formatMessage({id: 'channel_loader.someone', defaultMessage: 'Someone'}); const you = intl.formatMessage({id: 'combined_system_message.you', defaultMessage: 'You'}); @@ -120,6 +108,9 @@ const CombinedUserActivity = ({ }, [post, canDelete, isTablet, intl, location]); const renderMessage = (postType: string, userIds: string[], actorId: string) => { + if (!post) { + return null; + } let actor = ''; if (usernamesById[actorId]) { actor = `@${usernamesById[actorId]}`; @@ -177,9 +168,26 @@ const CombinedUserActivity = ({ }; useEffect(() => { - loadUserProfiles(); - }, [allUserIds, allUsernames]); + if (!post) { + return; + } + const {allUserIds, allUsernames} = post.props.user_activity; + if (allUserIds.length) { + fetchMissingProfilesByIds(serverUrl, allUserIds); + } + + if (allUsernames.length) { + fetchMissingProfilesByUsernames(serverUrl, allUsernames); + } + }, [post?.props.user_activity.allUserIds, post?.props.user_activity.allUsernames]); + + if (!post) { + return null; + } + + const itemTestID = `${testID}.${post.id}`; + const {messageData} = post.props.user_activity; for (const message of messageData) { const {postType, actorId} = message; const userIds = new Set(message.userIds); diff --git a/app/components/post_list/combined_user_activity/index.ts b/app/components/post_list/combined_user_activity/index.ts index 72bcfa6cb..32842e06e 100644 --- a/app/components/post_list/combined_user_activity/index.ts +++ b/app/components/post_list/combined_user_activity/index.ts @@ -28,24 +28,29 @@ const withCombinedPosts = withObservables(['postId'], ({database, postId}: WithD // Columns observed: `props` is used by `usernamesById`. `message` is used by generateCombinedPost. const posts = queryPostsById(database, postIds).observeWithColumns(['props', 'message']); - const post = posts.pipe(map((ps) => generateCombinedPost(postId, ps))); + const post = posts.pipe(map((ps) => (ps.length ? generateCombinedPost(postId, ps) : null))); const canDelete = combineLatest([posts, currentUser]).pipe( switchMap(([ps, u]) => (ps.length ? observePermissionForPost(database, ps[0], u, Permissions.DELETE_OTHERS_POSTS, false) : of$(false))), ); const usernamesById = post.pipe( switchMap( - (p) => queryUsersByIdsOrUsernames(database, p.props.user_activity.allUserIds, p.props.user_activity.allUsernames).observeWithColumns(['username']). - pipe( - // eslint-disable-next-line max-nested-callbacks - switchMap((users) => { + (p) => { + if (!p) { + return of$>({}); + } + return queryUsersByIdsOrUsernames(database, p.props.user_activity.allUserIds, p.props.user_activity.allUsernames).observeWithColumns(['username']). + pipe( // eslint-disable-next-line max-nested-callbacks - return of$(users.reduce((acc: Record, user) => { - acc[user.id] = user.username; - return acc; - }, {})); - }), - ), + switchMap((users) => { + // eslint-disable-next-line max-nested-callbacks + return of$(users.reduce((acc: Record, user) => { + acc[user.id] = user.username; + return acc; + }, {})); + }), + ); + }, ), ); From 3497318083a45fd20e433ea7ae8cea6982226b58 Mon Sep 17 00:00:00 2001 From: jannikb Date: Tue, 31 Oct 2023 17:33:08 +0100 Subject: [PATCH 21/23] fix: render latex in messages (#7635) Signed-off-by: Jannik Bertram Co-authored-by: Harrison Healey --- package-lock.json | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2283bdf25..dc6e5a2af 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "@voximplant/react-native-foreground-service": "3.0.2", "base-64": "1.0.0", "commonmark": "npm:@mattermost/commonmark@0.30.1-1", - "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#235bc817bcade503fb81fa51bbbe3c84f958ed12", + "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf", "deep-equal": "2.2.2", "deepmerge": "4.3.1", "emoji-regex": "10.2.1", @@ -9679,8 +9679,8 @@ }, "node_modules/commonmark-react-renderer": { "version": "4.3.5", - "resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#235bc817bcade503fb81fa51bbbe3c84f958ed12", - "integrity": "sha512-GP3+17loU8tNal91FAlqDcDyUHdhahMPpV/XBm++VAyoyvsGKx3wGQZY/cVKXNx+SV2UANXVf4VFx8GpAkqCBQ==", + "resolved": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#81b5d27509652bae50b4b510ede777dd3bd923cf", + "integrity": "sha512-2UYjN/Fix93L6udBsmZqCUggE7e5NA8rXHO2R3Dxs3lwHac3MsOMdEYZPST3Z/CCFc6gyKqWqDtCQXofbHffPA==", "license": "MIT", "dependencies": { "lodash.assign": "^4.2.0", @@ -30033,9 +30033,9 @@ } }, "commonmark-react-renderer": { - "version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#235bc817bcade503fb81fa51bbbe3c84f958ed12", - "integrity": "sha512-GP3+17loU8tNal91FAlqDcDyUHdhahMPpV/XBm++VAyoyvsGKx3wGQZY/cVKXNx+SV2UANXVf4VFx8GpAkqCBQ==", - "from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#235bc817bcade503fb81fa51bbbe3c84f958ed12", + "version": "git+ssh://git@github.com/mattermost/commonmark-react-renderer.git#81b5d27509652bae50b4b510ede777dd3bd923cf", + "integrity": "sha512-2UYjN/Fix93L6udBsmZqCUggE7e5NA8rXHO2R3Dxs3lwHac3MsOMdEYZPST3Z/CCFc6gyKqWqDtCQXofbHffPA==", + "from": "commonmark-react-renderer@github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf", "requires": { "lodash.assign": "^4.2.0", "lodash.isplainobject": "^4.0.6", diff --git a/package.json b/package.json index 14ce54531..2590a3e11 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,7 @@ "@voximplant/react-native-foreground-service": "3.0.2", "base-64": "1.0.0", "commonmark": "npm:@mattermost/commonmark@0.30.1-1", - "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#235bc817bcade503fb81fa51bbbe3c84f958ed12", + "commonmark-react-renderer": "github:mattermost/commonmark-react-renderer#81b5d27509652bae50b4b510ede777dd3bd923cf", "deep-equal": "2.2.2", "deepmerge": "4.3.1", "emoji-regex": "10.2.1", From 1904dfa4d14ce40bdbb598aa3c44cbd98a3e6a10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Espino=20Garc=C3=ADa?= Date: Wed, 1 Nov 2023 10:29:06 +0100 Subject: [PATCH 22/23] Bump app build number to 492 (#7645) --- android/app/build.gradle | 2 +- ios/Mattermost.xcodeproj/project.pbxproj | 8 ++++---- ios/Mattermost/Info.plist | 2 +- ios/MattermostShare/Info.plist | 2 +- ios/NotificationService/Info.plist | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 668e84164..9a47ac471 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -110,7 +110,7 @@ android { applicationId "com.mattermost.rnbeta" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 490 + versionCode 492 versionName "2.10.0" testBuildType System.getProperty('testBuildType', 'debug') testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index 8d45db34d..08fb2c014 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -1929,7 +1929,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 490; + CURRENT_PROJECT_VERSION = 492; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -1973,7 +1973,7 @@ CODE_SIGN_ENTITLEMENTS = Mattermost/Mattermost.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 490; + CURRENT_PROJECT_VERSION = 492; DEVELOPMENT_TEAM = UQ8HT4Q2XM; ENABLE_BITCODE = NO; HEADER_SEARCH_PATHS = ( @@ -2116,7 +2116,7 @@ CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 490; + CURRENT_PROJECT_VERSION = 492; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -2165,7 +2165,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 490; + CURRENT_PROJECT_VERSION = 492; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = UQ8HT4Q2XM; GCC_C_LANGUAGE_STANDARD = gnu11; diff --git a/ios/Mattermost/Info.plist b/ios/Mattermost/Info.plist index 27de4b73f..a6d40ce7a 100644 --- a/ios/Mattermost/Info.plist +++ b/ios/Mattermost/Info.plist @@ -37,7 +37,7 @@ CFBundleVersion - 490 + 492 ITSAppUsesNonExemptEncryption LSRequiresIPhoneOS diff --git a/ios/MattermostShare/Info.plist b/ios/MattermostShare/Info.plist index 006552425..03f703396 100644 --- a/ios/MattermostShare/Info.plist +++ b/ios/MattermostShare/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 2.10.0 CFBundleVersion - 490 + 492 UIAppFonts OpenSans-Bold.ttf diff --git a/ios/NotificationService/Info.plist b/ios/NotificationService/Info.plist index bbe279808..691c24829 100644 --- a/ios/NotificationService/Info.plist +++ b/ios/NotificationService/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 2.10.0 CFBundleVersion - 490 + 492 NSExtension NSExtensionPointIdentifier From a01fac47535066758109b1715bc529812aeaca45 Mon Sep 17 00:00:00 2001 From: rashmibharambe <93034034+rashmibharambe@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:08:57 +0530 Subject: [PATCH 23/23] Session timeout notification incorrectly says "Days" on iOS (#7629) * Session timeout notification incorrectly says "Days" on iOS * Update index.ts * Update index.ts * Update index.ts * Update index.ts * Update index.ts * Update index.ts * Session timeout notification incorrectly says "Days" on iOS * Update index.ts * Update en.json * Update index.ts --- app/utils/notification/index.ts | 25 ++++++++++++++++++++----- assets/base/i18n/en.json | 4 +++- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/app/utils/notification/index.ts b/app/utils/notification/index.ts index b53c096c8..8460de9c9 100644 --- a/app/utils/notification/index.ts +++ b/app/utils/notification/index.ts @@ -90,12 +90,27 @@ export const emitNotificationError = (type: 'Team' | 'Channel' | 'Post' | 'Conne export const scheduleExpiredNotification = (serverUrl: string, session: Session, serverName: string, locale = DEFAULT_LOCALE) => { const expiresAt = session?.expires_at || 0; - const expiresInDays = Math.ceil(Math.abs(moment.duration(moment().diff(moment(expiresAt))).asDays())); + const expiresInHours = Math.ceil(Math.abs(moment.duration(moment().diff(moment(expiresAt))).asHours())); + const expiresInDays = Math.floor(expiresInHours / 24); // Calculate expiresInDays + const remainingHours = expiresInHours % 24; // Calculate remaining hours const intl = createIntl({locale, messages: getTranslations(locale)}); - const body = intl.formatMessage({ - id: 'mobile.session_expired', - defaultMessage: 'Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.', - }, {siteName: serverName, daysCount: expiresInDays}); + let body = ''; + if (expiresInDays === 0) { + body = intl.formatMessage({ + id: 'mobile.session_expired_hrs', + defaultMessage: 'Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {hoursCount, number} {hoursCount, plural, one {hour} other {hours}}.', + }, {siteName: serverName, hoursCount: remainingHours}); + } else if (expiresInHours === 0) { + body = intl.formatMessage({ + id: 'mobile.session_expired_days', + defaultMessage: 'Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.', + }, {siteName: serverName, daysCount: expiresInDays}); + } else { + body = intl.formatMessage({ + id: 'mobile.session_expired_days_hrs', + defaultMessage: 'Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}} and {hoursCount, number} {hoursCount, plural, one {hour} other {hours}}.', + }, {siteName: serverName, daysCount: expiresInDays, hoursCount: remainingHours}); + } const title = intl.formatMessage({id: 'mobile.session_expired.title', defaultMessage: 'Session Expired'}); if (expiresAt) { diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index 1e4606926..985b58325 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -710,7 +710,9 @@ "mobile.server_url.deeplink.emm.denied": "This app is controlled by an EMM and the DeepLink server url does not match the EMM allowed server", "mobile.server_url.empty": "Please enter a valid server URL", "mobile.server_url.invalid_format": "URL must start with http:// or https://", - "mobile.session_expired": "Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.", + "mobile.session_expired_days": "Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}}.", + "mobile.session_expired_days_hrs": "Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {daysCount, number} {daysCount, plural, one {day} other {days}} and {hoursCount, number} {hoursCount, plural, one {hour} other {hours}}.", + "mobile.session_expired_hrs": "Please log in to continue receiving notifications. Sessions for {siteName} are configured to expire every {hoursCount, number} {hoursCount, plural, one {hour} other {hours}}.", "mobile.session_expired.title": "Session Expired", "mobile.set_status.dnd": "Do Not Disturb", "mobile.storage_permission_denied_description": "Upload files to your server. Open Settings to grant {applicationName} Read and Write access to files on this device.",