From 22884b53ad4daa2932aa8ed34fc5d5b928f8094d Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Thu, 20 Apr 2023 17:16:56 -0500 Subject: Thread muting [APP-29] (#500) * Implement thread muting * Apply filtering on background fetched notifs * Implement thread-muting tests --- src/view/com/util/forms/DropdownButton.tsx | 203 ++++++++++++++++++----------- 1 file changed, 126 insertions(+), 77 deletions(-) (limited to 'src/view/com/util/forms/DropdownButton.tsx') diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx index f21323efb..2aeae9bae 100644 --- a/src/view/com/util/forms/DropdownButton.tsx +++ b/src/view/com/util/forms/DropdownButton.tsx @@ -22,16 +22,22 @@ import {useTheme} from 'lib/ThemeContext' import {isAndroid, isIOS} from 'platform/detection' import Clipboard from '@react-native-clipboard/clipboard' import * as Toast from '../../util/Toast' +import {isWeb} from 'platform/detection' const HITSLOP = {left: 10, top: 10, right: 10, bottom: 10} -const ESTIMATED_MENU_ITEM_HEIGHT = 52 +const ESTIMATED_BTN_HEIGHT = 50 +const ESTIMATED_SEP_HEIGHT = 16 -export interface DropdownItem { +export interface DropdownItemButton { testID?: string icon?: IconProp label: string onPress: () => void } +export interface DropdownItemSeparator { + sep: true +} +export type DropdownItem = DropdownItemButton | DropdownItemSeparator type MaybeDropdownItem = DropdownItem | false | undefined export type DropdownButtonType = ButtonType | 'bare' @@ -59,10 +65,12 @@ export function DropdownButton({ rightOffset?: number bottomOffset?: number }) { - const ref = useRef(null) + const ref1 = useRef(null) + const ref2 = useRef(null) const onPress = () => { - ref.current?.measure( + const ref = ref1.current || ref2.current + ref?.measure( ( _x: number, _y: number, @@ -75,7 +83,14 @@ export function DropdownButton({ menuWidth = 200 } const winHeight = Dimensions.get('window').height - const estimatedMenuHeight = items.length * ESTIMATED_MENU_ITEM_HEIGHT + let estimatedMenuHeight = 0 + for (const item of items) { + if (item && isSep(item)) { + estimatedMenuHeight += ESTIMATED_SEP_HEIGHT + } else if (item && isBtn(item)) { + estimatedMenuHeight += ESTIMATED_BTN_HEIGHT + } + } const newX = openToRight ? pageX + width + rightOffset : pageX + width - menuWidth @@ -100,13 +115,13 @@ export function DropdownButton({ style={style} onPress={onPress} hitSlop={HITSLOP} - ref={ref}> + ref={ref1}> {children} ) } return ( - + @@ -122,8 +137,10 @@ export function PostDropdownBtn({ itemCid, itemHref, isAuthor, + isThreadMuted, onCopyPostText, onOpenTranslate, + onToggleThreadMute, onDeletePost, }: { testID?: string @@ -134,8 +151,10 @@ export function PostDropdownBtn({ itemHref: string itemTitle: string isAuthor: boolean + isThreadMuted: boolean onCopyPostText: () => void onOpenTranslate: () => void + onToggleThreadMute: () => void onDeletePost: () => void }) { const store = useStores() @@ -174,6 +193,16 @@ export function PostDropdownBtn({ } }, }, + {sep: true}, + { + testID: 'postDropdownMuteThreadBtn', + icon: 'comment-slash', + label: isThreadMuted ? 'Unmute thread' : 'Mute thread', + onPress() { + onToggleThreadMute() + }, + }, + {sep: true}, { testID: 'postDropdownReportBtn', icon: 'circle-exclamation', @@ -186,21 +215,19 @@ export function PostDropdownBtn({ }) }, }, - isAuthor - ? { - testID: 'postDropdownDeleteBtn', - icon: ['far', 'trash-can'], - label: 'Delete post', - onPress() { - store.shell.openModal({ - name: 'confirm', - title: 'Delete this post?', - message: 'Are you sure? This can not be undone.', - onPressConfirm: onDeletePost, - }) - }, - } - : undefined, + isAuthor && { + testID: 'postDropdownDeleteBtn', + icon: ['far', 'trash-can'], + label: 'Delete post', + onPress() { + store.shell.openModal({ + name: 'confirm', + title: 'Delete this post?', + message: 'Are you sure? This can not be undone.', + onPressConfirm: onDeletePost, + }) + }, + }, ].filter(Boolean) as DropdownItem[] return ( @@ -208,7 +235,7 @@ export function PostDropdownBtn({ testID={testID} style={style} items={dropdownItems} - menuWidth={200}> + menuWidth={isWeb ? 220 : 200}> {children} ) @@ -222,7 +249,10 @@ function createDropdownMenu( ): RootSiblings { const onPressItem = (index: number) => { sibling.destroy() - items[index].onPress() + const item = items[index] + if (isBtn(item)) { + item.onPress() + } } const onOuterPress = () => sibling.destroy() const sibling = new RootSiblings( @@ -240,6 +270,74 @@ function createDropdownMenu( return sibling } +type DropDownItemProps = { + onOuterPress: () => void + x: number + y: number + width: number + items: DropdownItem[] + onPressItem: (index: number) => void +} + +const DropdownItems = ({ + onOuterPress, + x, + y, + width, + items, + onPressItem, +}: DropDownItemProps) => { + const pal = usePalette('default') + const theme = useTheme() + const dropDownBackgroundColor = + theme.colorScheme === 'dark' ? pal.btn : pal.view + + return ( + <> + + + + + {items.map((item, index) => { + if (isBtn(item)) { + return ( + onPressItem(index)}> + {item.icon && ( + + )} + {item.label} + + ) + } else if (isSep(item)) { + return + } + return null + })} + + + ) +} + +function isSep(item: DropdownItem): item is DropdownItemSeparator { + return 'sep' in item && item.sep +} +function isBtn(item: DropdownItem): item is DropdownItemButton { + return !isSep(item) +} + const styles = StyleSheet.create({ bg: { position: 'absolute', @@ -277,57 +375,8 @@ const styles = StyleSheet.create({ label: { fontSize: 18, }, + separator: { + borderTopWidth: 1, + marginVertical: 8, + }, }) -type DropDownItemProps = { - onOuterPress: () => void - x: number - y: number - width: number - items: DropdownItem[] - onPressItem: (index: number) => void -} - -const DropdownItems = ({ - onOuterPress, - x, - y, - width, - items, - onPressItem, -}: DropDownItemProps) => { - const pal = usePalette('default') - const theme = useTheme() - const dropDownBackgroundColor = - theme.colorScheme === 'dark' ? pal.btn : pal.view - - return ( - <> - - - - - {items.map((item, index) => ( - onPressItem(index)}> - {item.icon && ( - - )} - {item.label} - - ))} - - - ) -} -- cgit 1.4.1