Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wallet Switcher v2 #6318

Draft
wants to merge 35 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
778117b
new wallet switcher UI
maxbbb Dec 10, 2024
74b4019
dnd flatlist autoscrolling
maxbbb Dec 10, 2024
71d6b46
fix layout/spacing issues
maxbbb Dec 11, 2024
e8fc4f8
pinned wallet grid edit mode jiggle animation
maxbbb Dec 11, 2024
2fa3f66
add long press option and optional callback data to dropdown menu com…
maxbbb Dec 12, 2024
089a164
address context menu on long press, refactor context menu to use new …
maxbbb Dec 12, 2024
4b8b989
add drag handler icon
maxbbb Dec 13, 2024
63d9683
selected wallet shadow, watching & hw wallet badge fixes
maxbbb Dec 13, 2024
54e2911
fix address label abbreviation & truncation
maxbbb Dec 13, 2024
2339bd0
fix total owned wallet balance formatting
maxbbb Dec 13, 2024
b85e0c7
fix autoscrolling can scroll logic & add inset behavior
maxbbb Dec 13, 2024
5134fcc
general purpose feature hint tooltip component
maxbbb Dec 14, 2024
a8ede2b
edit wallets hint tooltip
maxbbb Dec 14, 2024
10faef3
fix dnd provider gesture disabled toggle logic
maxbbb Dec 16, 2024
f69dcdf
add DraggableScrollView based on DraggableFlatList
maxbbb Dec 16, 2024
6455f0b
fix gesture problems by switching to draggable scrollview
maxbbb Dec 16, 2024
6cb4663
fixes for DnD children layout changes & draggable scrollview refactor
maxbbb Dec 17, 2024
e1bfada
fix different account emoji in list vs pinned grid
maxbbb Dec 17, 2024
e8d706d
dynamically size pinned account avatars
maxbbb Dec 17, 2024
b384ec7
copy & settings dropdown menu options, fix account emoji size
maxbbb Dec 17, 2024
8ed6aec
localization
maxbbb Dec 17, 2024
120483c
misc. styling fixes for light mode, android, design spec matching
maxbbb Dec 17, 2024
ccbf096
update dropdown menu component to work for checkbox & regular items
maxbbb Dec 18, 2024
8b63d33
tooltip localization
maxbbb Dec 18, 2024
45c4b1a
remove unused wallet item fields
maxbbb Dec 18, 2024
959b774
auto pin addresses
maxbbb Dec 18, 2024
1ec4446
refactor wallet list loading animation transition
maxbbb Dec 18, 2024
d137c40
autoscroll easing & scroll to end logic fix
maxbbb Dec 18, 2024
746b79b
fix remove pinned address logic
maxbbb Dec 18, 2024
b4c1691
integrate auto-pin wallet feature with backend implementation
maxbbb Dec 18, 2024
41925ed
misc. DnD bug fixes, worklet haptic activation, and styling cleanup
maxbbb Dec 18, 2024
50b5e04
fix dnd onUpdate logic, add onUpdateWorklet for haptic trigger on reo…
maxbbb Dec 18, 2024
dd774e2
android button & padding fixes, grid layout jank fix
maxbbb Dec 18, 2024
0b778ef
misc. cleanup
maxbbb Dec 19, 2024
aa75d33
Merge develop into @kane/APP-2081
maxbbb Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 34 additions & 10 deletions src/components/DropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ export const DropdownMenuRoot = DropdownMenuPrimitive.Root;
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
export const DropdownMenuContent = DropdownMenuPrimitive.Content;
export const DropdownMenuItem = DropdownMenuPrimitive.create(
styled(DropdownMenuPrimitive.Item)({
height: 34,
}),
'Item'
);
export const DropdownMenuCheckboxItem = DropdownMenuPrimitive.create(
styled(DropdownMenuPrimitive.CheckboxItem)({
height: 34,
}),
Expand All @@ -35,6 +41,7 @@ export type MenuItemIcon = Omit<IconConfig, 'iconValue' | 'iconType'> & (MenuIte
export type MenuItem<T> = Omit<MenuActionConfig, 'icon'> & {
actionKey: T;
actionTitle: string;
destructive?: boolean;
icon?: MenuItemIcon | { iconType: string; iconValue: string };
};

Expand All @@ -43,10 +50,13 @@ export type MenuConfig<T extends string> = Omit<_MenuConfig, 'menuItems' | 'menu
menuItems: Array<MenuItem<T>>;
};

type DropDownMenuProps<T extends string> = {
type DropDownMenuProps<T extends string, U extends Record<string, unknown> = never> = {
children: React.ReactElement;
menuConfig: MenuConfig<T>;
onPressMenuItem: (actionKey: T) => void;
triggerAction?: 'press' | 'longPress';
data?: U;
menuItemType?: 'checkbox';
} & DropdownMenuContentProps;

const buildIconConfig = (icon?: MenuItemIcon) => {
Expand All @@ -65,27 +75,36 @@ const buildIconConfig = (icon?: MenuItemIcon) => {
return null;
};

export function DropdownMenu<T extends string>({
export function DropdownMenu<T extends string, U extends Record<string, unknown> = never>({
children,
menuConfig,
onPressMenuItem,
data,
loop = true,
align = 'end',
sideOffset = 8,
side = 'right',
alignOffset = 5,
avoidCollisions = true,
}: DropDownMenuProps<T>) {
triggerAction = 'press',
menuItemType,
}: DropDownMenuProps<T, U>) {
const handleSelectItem = useCallback(
(actionKey: T) => {
onPressMenuItem(actionKey);
if (data !== undefined) {
(onPressMenuItem as (actionKey: T, data: U) => void)(actionKey, data);
} else {
(onPressMenuItem as (actionKey: T) => void)(actionKey);
}
},
[onPressMenuItem]
[onPressMenuItem, data]
);

const MenuItemComponent = menuItemType === 'checkbox' ? DropdownMenuCheckboxItem : DropdownMenuItem;

return (
<DropdownMenuRoot>
<DropdownMenuTrigger>{children}</DropdownMenuTrigger>
<DropdownMenuTrigger action={triggerAction}>{children}</DropdownMenuTrigger>
<DropdownMenuContent
loop={loop}
side={side}
Expand All @@ -97,19 +116,24 @@ export function DropdownMenu<T extends string>({
>
{!!menuConfig.menuTitle?.trim() && (
<DropdownMenuPrimitive.Group>
<DropdownMenuItem disabled>
<MenuItemComponent disabled>
<DropdownMenuItemTitle>{menuConfig.menuTitle}</DropdownMenuItemTitle>
</DropdownMenuItem>
</MenuItemComponent>
</DropdownMenuPrimitive.Group>
)}
{menuConfig.menuItems?.map(item => {
const Icon = buildIconConfig(item.icon as MenuItemIcon);

return (
<DropdownMenuItem value={item.menuState ?? 'off'} key={item.actionKey} onSelect={() => handleSelectItem(item.actionKey)}>
<MenuItemComponent
value={item.menuState ?? 'off'}
destructive={item.destructive}
key={item.actionKey}
onSelect={() => handleSelectItem(item.actionKey)}
>
<DropdownMenuItemTitle>{item.actionTitle}</DropdownMenuItemTitle>
{Icon}
</DropdownMenuItem>
</MenuItemComponent>
);
})}
</DropdownMenuContent>
Expand Down
2 changes: 1 addition & 1 deletion src/components/SmoothPager/ListPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export const TapToDismiss = memo(function TapToDismiss() {
});

const PANEL_INSET = 8;
const PANEL_WIDTH = DEVICE_WIDTH - PANEL_INSET * 2;
export const PANEL_WIDTH = DEVICE_WIDTH - PANEL_INSET * 2;
const PANEL_BORDER_RADIUS = 42;
const LIST_SCROLL_INDICATOR_BOTTOM_INSET = { bottom: PANEL_BORDER_RADIUS };

Expand Down
59 changes: 59 additions & 0 deletions src/components/animations/JiggleAnimation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { useEffect } from 'react';
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
withRepeat,
cancelAnimation,
useAnimatedReaction,
SharedValue,
withSequence,
} from 'react-native-reanimated';

type JiggleAnimationProps = {
amplitude?: number;
duration?: number;
children: React.ReactNode;
enabled: boolean | SharedValue<boolean>;
};

export function JiggleAnimation({ children, amplitude = 2, duration = 125, enabled }: JiggleAnimationProps) {
const rotation = useSharedValue(0);
const internalEnabled = useSharedValue(typeof enabled === 'boolean' ? enabled : false);

// slightly randomize duration to avoid sync with other jiggles
const instanceDuration = duration * (1 + (Math.random() - 0.5) * 0.2); // 10% variance
// randomize initial rotation direction to avoid sync with other jiggles
const initialRotation = Math.random() * amplitude;

useEffect(() => {
if (typeof enabled === 'boolean') {
internalEnabled.value = enabled;
}
}, [enabled, internalEnabled]);

useAnimatedReaction(
() => {
return typeof enabled === 'boolean' ? internalEnabled.value : (enabled as SharedValue<boolean>).value;
},
enabled => {
if (enabled) {
rotation.value = withSequence(
withTiming(initialRotation, { duration: instanceDuration / 2 }),
withRepeat(withTiming(-amplitude, { duration: instanceDuration }), -1, true)
);
} else {
cancelAnimation(rotation);
rotation.value = withTiming(0, { duration: instanceDuration / 2 });
}
}
);

const animatedStyle = useAnimatedStyle(() => {
return {
transform: [{ rotate: `${rotation.value}deg` }],
};
});

return <Animated.View style={animatedStyle}>{children}</Animated.View>;
}
2 changes: 1 addition & 1 deletion src/components/cards/MintsCard/Menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function Menu() {
);

return (
<DropdownMenu<MintsFilter> menuConfig={menuConfig} onPressMenuItem={onPressMenuItem}>
<DropdownMenu<MintsFilter> menuItemType="checkbox" menuConfig={menuConfig} onPressMenuItem={onPressMenuItem}>
<ButtonPressAnimation>
<Inset top="2px">
<Inline alignVertical="center" space={{ custom: 5 }}>
Expand Down
Loading
Loading