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

Privacy mode: instead of blurring, use an illegible font (#3376) #3377

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions packages/desktop-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"build"
],
"devDependencies": {
"@fontsource/redacted-script": "^5.0.21",
"@juggle/resize-observer": "^3.4.0",
"@playwright/test": "1.41.1",
"@rollup/plugin-inject": "^5.0.5",
Expand Down
86 changes: 54 additions & 32 deletions packages/desktop-client/src/components/PrivacyFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// @ts-strict-ignore
import React, {
useState,
useCallback,
Children,
type ComponentPropsWithRef,
type ReactNode,
} from 'react';

import { css } from 'glamor';

import { usePrivacyMode } from '../hooks/usePrivacyMode';
import { useResponsive } from '../ResponsiveProvider';

Expand Down Expand Up @@ -44,11 +44,9 @@ export function ConditionalPrivacyFilter({

type PrivacyFilterProps = ComponentPropsWithRef<typeof View> & {
activationFilters?: (boolean | (() => boolean))[];
blurIntensity?: number;
};
export function PrivacyFilter({
activationFilters,
blurIntensity,
children,
...props
}: PrivacyFilterProps) {
Expand All @@ -63,46 +61,70 @@ export function PrivacyFilter({
typeof value === 'boolean' ? value : value(),
));

const blurAmount = blurIntensity != null ? `${blurIntensity}px` : '3px';

return !activate ? (
<>{Children.toArray(children)}</>
) : (
<BlurredOverlay blurIntensity={blurAmount} {...props}>
{children}
</BlurredOverlay>
<PrivacyOverlay {...props}>{children}</PrivacyOverlay>
);
}

function BlurredOverlay({ blurIntensity, children, ...props }) {
const [hovered, setHovered] = useState(false);
const onHover = useCallback(() => setHovered(true), [setHovered]);
const onHoverEnd = useCallback(() => setHovered(false), [setHovered]);

const blurStyle = {
...(!hovered && {
filter: `blur(${blurIntensity})`,
WebkitFilter: `blur(${blurIntensity})`,
// To fix blur performance issue in Safari.
// https://graffino.com/til/CjT2jrcLHP-how-to-fix-filter-blur-performance-issue-in-safari
transform: `translate3d(0, 0, 0)`,
}),
};

function PrivacyOverlay({ children, ...props }) {
const { style, ...restProps } = props;

return (
<View
style={{
display: style?.display ? style.display : 'inline-flex',
...blurStyle,
...style,
}}
onPointerEnter={onHover}
onPointerLeave={onHoverEnd}
className={`${css(
[
{
display: 'inline-flex',
flexGrow: 1,
position: 'relative',
Copy link
Contributor Author

@olets olets Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially breaking. I didn't notice any instances where PrivacyFilter content is positioned relative to something higher up the DOM. Doesn't break the visual tests, but I don't know how completely those cover the app. If someone else knows that this will be a problem, lmk

' > div:first-child': {
opacity: 0,
},
' > div:nth-child(2)': {
display: 'flex',
},
'&:hover': {
' > div:first-child': {
opacity: 1,
},
' > div:nth-child(2)': {
display: 'none',
},
},
},
],
style,
)}`}
{...restProps}
>
{children}
<div
className={`${css([
{
display: 'flex',
flexGrow: 1,
},
])}`}
>
{children}
</div>

<div
aria-hidden="true"
className={`${css({
flexDirection: 'column',
fontFamily: 'Redacted Script',
height: '100%',
inset: 0,
justifyContent: 'center',
pointerEvents: 'none',
position: 'absolute',
width: '100%',
})}`}
>
{children}
</div>
matt-fidd marked this conversation as resolved.
Show resolved Hide resolved
matt-fidd marked this conversation as resolved.
Show resolved Hide resolved
</View>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,6 @@ export const ExpenseGroupMonth = memo(function ExpenseGroupMonth({
valueProps={{
binding: envelopeBudget.groupBalance(id),
type: 'financial',
privacyFilter: {
style: {
paddingRight: styles.monthRightPadding,
},
},
}}
/>
</View>
Expand Down Expand Up @@ -431,11 +426,6 @@ export function IncomeGroupMonth({ month }: IncomeGroupMonthProps) {
valueProps={{
binding: envelopeBudget.groupIncomeReceived,
type: 'financial',
privacyFilter: {
style: {
paddingRight: styles.monthRightPadding,
},
},
}}
/>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ export function ToBudgetAmount({
offset={3}
triggerProps={{ isDisabled: isTotalsListTooltipDisabled }}
>
<PrivacyFilter blurIntensity={7}>
<PrivacyFilter
style={{
textAlign: 'center',
}}
>
<Block
onClick={onClick}
data-cellname={sheetName}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,11 +178,6 @@ export const GroupMonth = memo(function GroupMonth({
valueProps={{
binding: trackingBudget.groupBalance(id),
type: 'financial',
privacyFilter: {
style: {
paddingRight: styles.monthRightPadding,
},
},
}}
/>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,7 @@ export function Saved({ projected, style }: SavedProps) {
},
])}`}
>
<PrivacyFilter blurIntensity={7}>
{format(saved, 'financial')}
</PrivacyFilter>
<PrivacyFilter>{format(saved, 'financial')}</PrivacyFilter>
</View>
</Tooltip>
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,7 @@ export function ReportSummary({
fontWeight: 800,
}}
>
<PrivacyFilter blurIntensity={7}>
{amountToCurrency(data[balanceTypeOp])}
</PrivacyFilter>
<PrivacyFilter>{amountToCurrency(data[balanceTypeOp])}</PrivacyFilter>
</Text>
<Text style={{ fontWeight: 600 }}>For this time period</Text>
</View>
Expand Down Expand Up @@ -154,7 +152,7 @@ export function ReportSummary({
fontWeight: 800,
}}
>
<PrivacyFilter blurIntensity={7}>
<PrivacyFilter>
{!isNaN(average) && integerToCurrency(Math.round(average))}
</PrivacyFilter>
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,7 @@ export function CustomReport() {
left={<Block>{balanceType}:</Block>}
right={
<Text>
<PrivacyFilter blurIntensity={5}>
<PrivacyFilter>
{amountToCurrency(data[balanceTypeOp])}
</PrivacyFilter>
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,7 @@ function NetWorthInner({ widget }) {
<View
style={{ ...styles.largeText, fontWeight: 400, marginBottom: 5 }}
>
<PrivacyFilter blurIntensity={5}>
{integerToCurrency(data.netWorth)}
</PrivacyFilter>
<PrivacyFilter>{integerToCurrency(data.netWorth)}</PrivacyFilter>
</View>
<PrivacyFilter>
<Change amount={data.totalChange} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) {
}
right={
<Text style={{ fontWeight: 600 }}>
<PrivacyFilter blurIntensity={5}>
<PrivacyFilter>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].compare),
)}
Expand All @@ -494,7 +494,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) {
}
right={
<Text style={{ fontWeight: 600 }}>
<PrivacyFilter blurIntensity={5}>
<PrivacyFilter>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].compareTo),
)}
Expand All @@ -515,7 +515,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) {
}
right={
<Text style={{ fontWeight: 600 }}>
<PrivacyFilter blurIntensity={5}>
<PrivacyFilter>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].budget),
)}
Expand All @@ -535,7 +535,7 @@ function SpendingInternal({ widget }: SpendingInternalProps) {
}
right={
<Text style={{ fontWeight: 600 }}>
<PrivacyFilter blurIntensity={5}>
<PrivacyFilter>
{amountToCurrency(
Math.abs(data.intervalData[todayDay].average),
)}
Expand Down
5 changes: 0 additions & 5 deletions packages/desktop-client/src/components/table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,11 +197,6 @@ export function Cell({
privacyFilter={mergeConditionalPrivacyFilterProps(
{
activationFilters: [!focused, !exposed],
style: {
position: 'absolute',
width: '100%',
height: '100%',
},
Comment on lines -200 to -204
Copy link
Contributor Author

@olets olets Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This appears to be safe to remove. But I'm also not sure why it's in current master. So I may be missing some edge case not covered by the visual tests, and this might need to be reverted.

},
privacyFilter,
)}
Expand Down
2 changes: 2 additions & 0 deletions packages/desktop-client/src/fonts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
$inter-font-path: '../../../node_modules/inter-ui/Inter (web)'
);
@include variable.default;

@import "@fontsource/redacted-script";
6 changes: 6 additions & 0 deletions upcoming-release-notes/3377.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
category: Enhancements
authors: [olets]
---

Privacy mode: instead of blurring, use an illegible font (#3376)
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@actual-app/web@workspace:packages/desktop-client"
dependencies:
"@fontsource/redacted-script": "npm:^5.0.21"
"@juggle/resize-observer": "npm:^3.4.0"
"@playwright/test": "npm:1.41.1"
"@rollup/plugin-inject": "npm:^5.0.5"
Expand Down Expand Up @@ -1846,6 +1847,13 @@ __metadata:
languageName: node
linkType: hard

"@fontsource/redacted-script@npm:^5.0.21":
version: 5.0.21
resolution: "@fontsource/redacted-script@npm:5.0.21"
checksum: 10/93f506c9e8df827ab1872d433a09079c592f3a20a1c36b9a168e68377967d3d1d282fffd51bee973c2ecb253316ff4641d244f8f05242e4aa968a1eb14d065eb
languageName: node
linkType: hard

"@formatjs/ecma402-abstract@npm:1.15.0":
version: 1.15.0
resolution: "@formatjs/ecma402-abstract@npm:1.15.0"
Expand Down
Loading