diff --git a/lib/utils/message-pinning-utils.js b/lib/utils/message-pinning-utils.js
index 0383ee548..cab30ba76 100644
--- a/lib/utils/message-pinning-utils.js
+++ b/lib/utils/message-pinning-utils.js
@@ -1,32 +1,48 @@
// @flow
import { isInvalidPinSourceForThread } from '../shared/message-utils.js';
-import { threadHasPermission } from '../shared/thread-utils.js';
+import {
+ threadHasPermission,
+ useThreadHasPermission,
+} from '../shared/thread-utils.js';
import type { MessageInfo, RawMessageInfo } from '../types/message-types.js';
import type {
ThreadInfo,
RawThreadInfo,
} from '../types/minimally-encoded-thread-permissions-types.js';
import { threadPermissions } from '../types/thread-permission-types.js';
import type { LegacyRawThreadInfo } from '../types/thread-types.js';
function canToggleMessagePin(
messageInfo: RawMessageInfo | MessageInfo,
threadInfo: LegacyRawThreadInfo | RawThreadInfo | ThreadInfo,
): boolean {
const isValidMessage = !isInvalidPinSourceForThread(messageInfo, threadInfo);
const hasManagePinsPermission = threadHasPermission(
threadInfo,
threadPermissions.MANAGE_PINS,
);
return isValidMessage && hasManagePinsPermission;
}
+function useCanToggleMessagePin(
+ messageInfo: RawMessageInfo | MessageInfo,
+ threadInfo: ThreadInfo,
+): boolean {
+ const isValidMessage = !isInvalidPinSourceForThread(messageInfo, threadInfo);
+ const hasManagePinsPermission = useThreadHasPermission(
+ threadInfo,
+ threadPermissions.MANAGE_PINS,
+ );
+
+ return isValidMessage && hasManagePinsPermission;
+}
+
function pinnedMessageCountText(pinnedCount: number): string {
const messageNoun = pinnedCount === 1 ? 'message' : 'messages';
return `${pinnedCount} pinned ${messageNoun}`;
}
-export { canToggleMessagePin, pinnedMessageCountText };
+export { canToggleMessagePin, useCanToggleMessagePin, pinnedMessageCountText };
diff --git a/native/chat/message.react.js b/native/chat/message.react.js
index 2b748d36d..be1f1b4b4 100644
--- a/native/chat/message.react.js
+++ b/native/chat/message.react.js
@@ -1,162 +1,162 @@
// @flow
import * as React from 'react';
import {
LayoutAnimation,
TouchableWithoutFeedback,
PixelRatio,
} from 'react-native';
import { messageKey } from 'lib/shared/message-utils.js';
-import { canToggleMessagePin } from 'lib/utils/message-pinning-utils.js';
+import { useCanToggleMessagePin } from 'lib/utils/message-pinning-utils.js';
import type { ChatNavigationProp } from './chat.react.js';
import MultimediaMessage from './multimedia-message.react.js';
import { RobotextMessage } from './robotext-message.react.js';
import { TextMessage } from './text-message.react.js';
import { messageItemHeight } from './utils.js';
import { KeyboardContext } from '../keyboard/keyboard-state.js';
import type { AppNavigationProp } from '../navigation/app-navigator.react';
import type { NavigationRoute } from '../navigation/route-names.js';
import type { ChatMessageInfoItemWithHeight } from '../types/chat-types.js';
import { type VerticalBounds } from '../types/layout-types.js';
import type { LayoutEvent } from '../types/react-native.js';
type Props = {
+item: ChatMessageInfoItemWithHeight,
+focused: boolean,
+navigation:
| ChatNavigationProp<'MessageList'>
| AppNavigationProp<'TogglePinModal'>
| ChatNavigationProp<'PinnedMessagesScreen'>
| ChatNavigationProp<'MessageSearch'>,
+route:
| NavigationRoute<'MessageList'>
| NavigationRoute<'TogglePinModal'>
| NavigationRoute<'PinnedMessagesScreen'>
| NavigationRoute<'MessageSearch'>,
+toggleFocus: (messageKey: string) => void,
+verticalBounds: ?VerticalBounds,
shouldDisplayPinIndicator: boolean,
};
function Message(props: Props): React.Node {
const {
focused,
item,
navigation,
route,
toggleFocus,
verticalBounds,
shouldDisplayPinIndicator,
} = props;
const focusedOrStartsConversation = focused || item.startsConversation;
React.useEffect(() => {
LayoutAnimation.easeInEaseOut();
}, [focusedOrStartsConversation]);
const keyboardState = React.useContext(KeyboardContext);
const dismissKeyboard = keyboardState?.dismissKeyboard;
const onMessagePress = React.useCallback(
() => dismissKeyboard?.(),
[dismissKeyboard],
);
const onLayout = React.useCallback(
(event: LayoutEvent) => {
if (focused) {
return;
}
const measuredHeight = event.nativeEvent.layout.height;
const expectedHeight = messageItemHeight(item);
const pixelRatio = 1 / PixelRatio.get();
const distance = Math.abs(measuredHeight - expectedHeight);
if (distance < pixelRatio) {
return;
}
const approxMeasuredHeight = Math.round(measuredHeight * 100) / 100;
const approxExpectedHeight = Math.round(expectedHeight * 100) / 100;
console.log(
`Message height for ${item.messageShapeType} ` +
`${messageKey(item.messageInfo)} was expected to be ` +
`${approxExpectedHeight} but is actually ${approxMeasuredHeight}. ` +
"This means MessageList's FlatList isn't getting the right item " +
'height for some of its nodes, which is guaranteed to cause glitchy ' +
'behavior. Please investigate!!',
);
},
[focused, item],
);
- const canTogglePins = React.useMemo(
- () => canToggleMessagePin(props.item.messageInfo, props.item.threadInfo),
- [props.item.messageInfo, props.item.threadInfo],
+ const canTogglePins = useCanToggleMessagePin(
+ props.item.messageInfo,
+ props.item.threadInfo,
);
const innerMessageNode = React.useMemo(() => {
if (item.messageShapeType === 'text') {
return (
);
} else if (item.messageShapeType === 'multimedia') {
return (
);
} else {
return (
);
}
}, [
focused,
item,
navigation,
route,
shouldDisplayPinIndicator,
toggleFocus,
verticalBounds,
canTogglePins,
]);
const message = React.useMemo(
() => (
{innerMessageNode}
),
[innerMessageNode, onLayout, onMessagePress],
);
return message;
}
export default Message;