Skip to content

Commit

Permalink
Various Fixes (#8212)
Browse files Browse the repository at this point in the history
  • Loading branch information
enahum authored Sep 12, 2024
1 parent 20d248f commit 394da44
Show file tree
Hide file tree
Showing 21 changed files with 258 additions and 76 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {Button} from '@rneui/base';
import React, {useCallback, useEffect, useMemo, useState} from 'react';
import {useIntl, type IntlShape} from 'react-intl';
import {Alert, StyleSheet} from 'react-native';
import Animated from 'react-native-reanimated';
import {useSafeAreaInsets} from 'react-native-safe-area-context';

import {ITEM_HEIGHT} from '@components/option_item';
Expand Down Expand Up @@ -149,20 +150,19 @@ const ChannelBookmark = ({
}

return (
<Button
containerStyle={styles.container}
buttonStyle={styles.button}
onPress={onGestureEvent}
onLongPress={handleLongPress}

// @ts-expect-error ref not present in TS def
ref={ref}
>
<BookmarkDetails
bookmark={bookmark}
file={file}
/>
</Button>
<Animated.View ref={ref}>
<Button
containerStyle={styles.container}
buttonStyle={styles.button}
onPress={onGestureEvent}
onLongPress={handleLongPress}
>
<BookmarkDetails
bookmark={bookmark}
file={file}
/>
</Button>
</Animated.View>
);
};

Expand Down
19 changes: 18 additions & 1 deletion app/hooks/device.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

import RNUtils, {type WindowDimensions} from '@mattermost/rnutils';
import React, {type RefObject, useEffect, useRef, useState, useContext} from 'react';
import {AppState, DeviceEventEmitter, Keyboard, Platform, useWindowDimensions, View} from 'react-native';
import {AppState, DeviceEventEmitter, Keyboard, NativeEventEmitter, Platform, View} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';

import {DeviceContext} from '@context/device';

import type {KeyboardTrackingViewRef, KeyboardWillShowEventData} from '@mattermost/keyboard-tracker';

const utilsEmitter = new NativeEventEmitter(RNUtils);

export function useSplitView() {
const {isSplit} = React.useContext(DeviceContext);
return isSplit;
Expand All @@ -28,6 +31,20 @@ export function useAppState() {
return appState;
}

export function useWindowDimensions() {
const [dimensions, setDimensions] = useState(RNUtils.getWindowDimensions());

useEffect(() => {
const listener = utilsEmitter.addListener('DimensionsChanged', (window: WindowDimensions) => {
setDimensions(window);
});

return () => listener.remove();
}, []);

return dimensions;
}

export function useIsTablet() {
const {isSplit, isTablet} = useContext(DeviceContext);
return isTablet && !isSplit;
Expand Down
6 changes: 3 additions & 3 deletions app/screens/gallery/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

import RNUtils from '@mattermost/rnutils';
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useWindowDimensions, Platform} from 'react-native';
import {Platform} from 'react-native';

import {CaptionsEnabledContext} from '@calls/context';
import {hasCaptions} from '@calls/utils';
import useAndroidHardwareBackHandler from '@hooks/android_back_handler';
import {useIsTablet} from '@hooks/device';
import {useIsTablet, useWindowDimensions} from '@hooks/device';
import {useGalleryControls} from '@hooks/gallery';
import {dismissOverlay, setScreensOrientation} from '@screens/navigation';
import {freezeOtherScreens} from '@utils/gallery';
Expand All @@ -35,7 +35,7 @@ const GalleryScreen = ({componentId, galleryIdentifier, hideActions, initialInde
const [captionsEnabled, setCaptionsEnabled] = useState<boolean[]>(new Array(items.length).fill(true));
const [captionsAvailable, setCaptionsAvailable] = useState<boolean[]>([]);
const {setControlsHidden, headerStyles, footerStyles} = useGalleryControls();
const dimensions = useMemo(() => ({width: dim.width, height: dim.height}), [dim.width]);
const dimensions = useMemo(() => ({width: dim.width, height: dim.height}), [dim]);
const galleryRef = useRef<GalleryRef>(null);

useEffect(() => {
Expand Down
17 changes: 4 additions & 13 deletions app/screens/gallery/video_renderer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// See LICENSE.txt for license information.

import React, {useCallback, useContext, useEffect, useMemo, useRef, useState} from 'react';
import {DeviceEventEmitter, StyleSheet, useWindowDimensions} from 'react-native';
import {DeviceEventEmitter, StyleSheet} from 'react-native';
import Animated, {
Easing,
useAnimatedStyle,
Expand Down Expand Up @@ -47,7 +47,6 @@ const styles = StyleSheet.create({
});

const VideoRenderer = ({height, index, initialIndex, item, isPageActive, onShouldHideControls, width}: VideoRendererProps) => {
const dimensions = useWindowDimensions();
const fullscreen = useSharedValue(false);
const {bottom} = useSafeAreaInsets();
const serverUrl = useServerUrl();
Expand Down Expand Up @@ -126,23 +125,15 @@ const VideoRenderer = ({height, index, initialIndex, item, isPageActive, onShoul
}, []);

const dimensionsStyle = useMemo(() => {
let w = width;
let h = height - (VIDEO_INSET + GALLERY_FOOTER_HEIGHT + bottom);
const w = width;
const h = height - (VIDEO_INSET + GALLERY_FOOTER_HEIGHT + bottom);

if (hasError) {
return {height: 0, width: 0};
}

if (fullscreen.value) {
w = dimensions.width;
h = dimensions.height;
} else if (dimensions.width > dimensions.height) {
w = h;
h = width;
}

return {width: w, height: h};
}, [hasError, fullscreen.value, dimensions.height]);
}, [hasError, fullscreen.value, height, width]);

const animatedStyle = useAnimatedStyle(() => {
return {
Expand Down
2 changes: 1 addition & 1 deletion app/screens/gallery/viewer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ const GalleryViewer = ({
}

return (<ImageRenderer {...props}/>);
}, [items]);
}, [items, width, height]);

return (
<Pager
Expand Down
65 changes: 47 additions & 18 deletions app/utils/deep_link/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@ import {getIntlShape} from '@utils/general';
import {logError} from '@utils/log';
import {escapeRegex} from '@utils/markdown';
import {addNewServer} from '@utils/server';
import {removeProtocol, stripTrailingSlashes} from '@utils/url';
import {
TEAM_NAME_PATH_PATTERN,
IDENTIFIER_PATH_PATTERN,
ID_PATH_PATTERN,
} from '@utils/url/path';

import {removeProtocol} from '../url';

import type {DeepLinkChannel, DeepLinkDM, DeepLinkGM, DeepLinkPermalink, DeepLinkWithData, LaunchProps} from '@typings/launch';
import type {AvailableScreens} from '@typings/screens/navigation';

Expand Down Expand Up @@ -121,29 +120,30 @@ export async function handleDeepLink(deepLinkUrl: string, intlShape?: IntlShape,

type ChannelPathParams = {
hostname: string;
serverUrl: string;
serverUrl: string[];
teamName: string;
path: 'channels' | 'messages';
identifier: string;
};

const CHANNEL_PATH = `:serverUrl(.*)/:teamName(${TEAM_NAME_PATH_PATTERN})/:path(channels|messages)/:identifier(${IDENTIFIER_PATH_PATTERN})`;
const CHANNEL_PATH = '*serverUrl/:teamName/:path/:identifier';
export const matchChannelDeeplink = match<ChannelPathParams>(CHANNEL_PATH);

type PermalinkPathParams = {
serverUrl: string;
serverUrl: string[];
teamName: string;
postId: string;
};
const PERMALINK_PATH = `:serverUrl(.*)/:teamName(${TEAM_NAME_PATH_PATTERN})/pl/:postId(${ID_PATH_PATTERN})`;
const PERMALINK_PATH = '*serverUrl/:teamName/pl/:postId';
export const matchPermalinkDeeplink = match<PermalinkPathParams>(PERMALINK_PATH);

type ServerPathParams = {
serverUrl: string;
path: string;
subpath?: string[];
}

export const matchServerDeepLink = match<ServerPathParams>(':serverUrl(.*)/:path(.*)', {decode: decodeURIComponent});
export const matchServerDeepLink = match<ServerPathParams>(':serverUrl/{:path}{/*subpath}', {decode: decodeURIComponent});
const reservedWords = ['login', 'signup', 'admin_console'];

export function extractServerUrl(url: string) {
Expand All @@ -168,43 +168,72 @@ export function extractServerUrl(url: string) {
const matched = matchServerDeepLink(deepLinkUrl);

if (matched) {
const {path} = matched.params;
const segments = path.split('/');
const {path, subpath} = matched.params;

if (segments.length > 0 && reservedWords.includes(segments[segments.length - 1])) {
return matched.params.serverUrl;
let extra = '';

if (!path || reservedWords.includes(path)) {
return stripTrailingSlashes(matched.params.serverUrl);
}
return path ? `${matched.params.serverUrl}/${path}` : matched.params.serverUrl;

if (subpath && subpath.length > 0) {
if (reservedWords.includes(subpath[subpath.length - 1])) {
subpath.pop();
}

extra = subpath.join('/');
}

if (extra) {
return stripTrailingSlashes(`${matched.params.serverUrl}/${path}/${extra}`);
}

return stripTrailingSlashes(`${matched.params.serverUrl}/${path}`);
}

return deepLinkUrl;
}

function isValidTeamName(teamName: string): boolean {
const regex = new RegExp(`^${TEAM_NAME_PATH_PATTERN}$`);
return regex.test(teamName);
}

function isValidIdentifierPathPattern(id: string): boolean {
const regex = new RegExp(`^${IDENTIFIER_PATH_PATTERN}$`);
return regex.test(id);
}

function isValidPostId(id: string): boolean {
const regex = new RegExp(`^${ID_PATH_PATTERN}$`);
return regex.test(id);
}

export function parseDeepLink(deepLinkUrl: string, asServer = false): DeepLinkWithData {
try {
const url = removeProtocol(deepLinkUrl);

const channelMatch = matchChannelDeeplink(url);
if (channelMatch) {
if (channelMatch && isValidTeamName(channelMatch.params.teamName) && isValidIdentifierPathPattern(channelMatch.params.identifier)) {
const {params: {serverUrl, teamName, path, identifier}} = channelMatch;

if (path === 'channels') {
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl, teamName, channelName: identifier}};
return {type: DeepLink.Channel, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, channelName: identifier}};
}

if (path === 'messages') {
if (identifier.startsWith('@')) {
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl, teamName, userName: identifier.substring(1)}};
return {type: DeepLink.DirectMessage, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, userName: identifier.substring(1)}};
}

return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl, teamName, channelName: identifier}};
return {type: DeepLink.GroupMessage, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, channelName: identifier}};
}
}

const permalinkMatch = matchPermalinkDeeplink(url);
if (permalinkMatch) {
if (permalinkMatch && isValidTeamName(permalinkMatch.params.teamName) && isValidPostId(permalinkMatch.params.postId)) {
const {params: {serverUrl, teamName, postId}} = permalinkMatch;
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl, teamName, postId}};
return {type: DeepLink.Permalink, url: deepLinkUrl, data: {serverUrl: serverUrl.join('/'), teamName, postId}};
}

if (asServer) {
Expand Down
16 changes: 7 additions & 9 deletions fastlane/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ GEM
artifactory (3.0.17)
atomos (0.1.3)
aws-eventstream (1.3.0)
aws-partitions (1.966.0)
aws-sdk-core (3.201.5)
aws-partitions (1.973.0)
aws-sdk-core (3.204.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.9)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.88.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-kms (1.90.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.159.0)
aws-sdk-core (~> 3, >= 3.201.0)
aws-sdk-s3 (1.161.0)
aws-sdk-core (~> 3, >= 3.203.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5)
aws-sigv4 (1.9.1)
Expand Down Expand Up @@ -188,8 +188,7 @@ GEM
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
rexml (3.3.5)
strscan
rexml (3.3.7)
rouge (2.0.7)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
Expand All @@ -202,7 +201,6 @@ GEM
simctl (1.6.10)
CFPropertyList
naturally
strscan (3.1.0)
terminal-notifier (2.0.0)
terminal-table (3.0.2)
unicode-display_width (>= 1.1.1, < 3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ class RNUtilsModuleImpl(private val reactContext: ReactApplicationContext) {
return SplitView.isRunningInSplitView()
}

fun getWindowDimensions(): WritableMap? {
return SplitView.getWindowDimensions()
}

fun unlockOrientation() {}

fun lockPortrait() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ package com.mattermost.rnutils.enums

enum class Events(val event: String) {
SAVE_ERROR_EVENT("SaveError"),
SPLIT_VIEW_CHANGED("SplitViewChanged")
SPLIT_VIEW_CHANGED("SplitViewChanged"),
DIMENSIONS_CHANGED("DimensionsChanged")
}
Loading

0 comments on commit 394da44

Please sign in to comment.