Skip to content

Commit

Permalink
Merge pull request #3825 from tloncorp/native-group-volume
Browse files Browse the repository at this point in the history
native: group and channel volume settings from the chat options sheet
  • Loading branch information
latter-bolden authored Aug 15, 2024
2 parents f0d98ec + 1a6ce1a commit ce4e39e
Show file tree
Hide file tree
Showing 25 changed files with 803 additions and 211 deletions.
4 changes: 2 additions & 2 deletions apps/tlon-mobile/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1130,7 +1130,7 @@ PODS:
- React-Core
- react-native-netinfo (11.1.0):
- React-Core
- react-native-safe-area-context (4.8.2):
- react-native-safe-area-context (4.9.0):
- React-Core
- react-native-webview (13.6.4):
- glog
Expand Down Expand Up @@ -1787,7 +1787,7 @@ SPEC CHECKSUMS:
react-native-context-menu-view: dcec18eb8882e20596dbb75802e7d19cb87dac02
react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06
react-native-netinfo: 3aa5637c18834966e0c932de8ae1ae56fea20a97
react-native-safe-area-context: 0ee144a6170530ccc37a0fd9388e28d06f516a89
react-native-safe-area-context: b97eb6f9e3b7f437806c2ce5983f479f8eb5de4b
react-native-webview: 1f6c37318115b6e96285e0b06770307d9a751bb8
React-nativeconfig: ca8b90c736cf3be019cb332ca42d93dd95b32e05
React-NativeModulesApple: 1fdffcce7772e274baeab33a1900f45feba86cbd
Expand Down
142 changes: 124 additions & 18 deletions apps/tlon-mobile/src/screens/PushNotificationSettingsScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,35 +1,60 @@
import { NativeStackScreenProps } from '@react-navigation/native-stack';
import * as db from '@tloncorp/shared/dist/db';
import * as logic from '@tloncorp/shared/dist/logic';
import * as store from '@tloncorp/shared/dist/store';
import * as ub from '@tloncorp/shared/dist/urbit';
import {
ChannelListItem,
GenericHeader,
GroupListItem,
Icon,
ListItem,
ScrollView,
SizableText,
View,
XStack,
YStack,
} from '@tloncorp/ui';
import { useCallback } from 'react';
import { ComponentProps, useCallback, useMemo } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';

import { RootStackParamList } from '../types';

type Props = NativeStackScreenProps<RootStackParamList, 'AppSettings'>;

export function PushNotificationSettingsScreen(props: Props) {
const { data: pushNotificationsSetting } =
store.usePushNotificationsSetting();
const baseVolumeSetting = store.useBaseVolumeLevel();
const { data: exceptions } = store.useVolumeExceptions();

const numExceptions = useMemo(
() =>
(exceptions?.channels.length ?? 0) + (exceptions?.groups.length ?? 0) ??
0,
[exceptions]
);

const setLevel = useCallback(
async (level: ub.PushNotificationsSetting) => {
if (level === pushNotificationsSetting) return;
await store.setDefaultNotificationLevel(level);
async (level: ub.NotificationLevel) => {
if (level === baseVolumeSetting) return;
await store.setBaseVolumeLevel({ level });
},
[baseVolumeSetting]
);

const removeException = useCallback(
async (exception: db.Group | db.Channel) => {
if (logic.isGroup(exception)) {
await store.setGroupVolumeLevel({ group: exception, level: null });
} else {
await store.setChannelVolumeLevel({ channel: exception, level: null });
}
},
[pushNotificationsSetting]
[]
);

const LevelIndicator = useCallback(
(props: { level: ub.PushNotificationsSetting }) => {
if (pushNotificationsSetting === props.level) {
(props: { levels: ub.NotificationLevel[] }) => {
if (props.levels.includes(baseVolumeSetting)) {
return (
<View
height="$2xl"
Expand All @@ -52,28 +77,28 @@ export function PushNotificationSettingsScreen(props: Props) {
/>
);
},
[pushNotificationsSetting]
[baseVolumeSetting]
);

return (
<View>
<View flex={1}>
<GenericHeader
title="Push Notifications"
goBack={() => props.navigation.goBack()}
/>
<View marginTop="$m" marginHorizontal="$2xl">
<View marginTop="$m" marginHorizontal="$2xl" flex={1}>
<SizableText marginLeft="$m" marginTop="$xl" size="$m">
Configure what kinds of messages will send you notifications.
</SizableText>

<YStack marginLeft="$m" marginTop="$3xl">
<XStack onPress={() => setLevel('all')}>
<LevelIndicator level="all" />
<XStack onPress={() => setLevel('medium')}>
<LevelIndicator levels={['loud', 'medium']} />
<SizableText marginLeft="$l">All group activity</SizableText>
</XStack>

<XStack marginTop="$xl" onPress={() => setLevel('some')}>
<LevelIndicator level="some" />
<XStack marginTop="$xl" onPress={() => setLevel('soft')}>
<LevelIndicator levels={['soft', 'default']} />
<YStack marginLeft="$l">
<SizableText>Mentions and replies only</SizableText>
<SizableText
Expand All @@ -87,12 +112,93 @@ export function PushNotificationSettingsScreen(props: Props) {
</YStack>
</XStack>

<XStack marginTop="$xl" onPress={() => setLevel('none')}>
<LevelIndicator level="none" />
<XStack marginTop="$xl" onPress={() => setLevel('hush')}>
<LevelIndicator levels={['hush']} />
<SizableText marginLeft="$l">Nothing</SizableText>
</XStack>
</YStack>

{numExceptions > 0 ? (
<ExceptionsDisplay
marginTop="$2xl"
channels={exceptions?.channels ?? []}
groups={exceptions?.groups ?? []}
removeException={removeException}
/>
) : null}
</View>
</View>
);
}

export function ExceptionsDisplay({
groups,
channels,
removeException,
...rest
}: {
groups: db.Group[];
channels: db.Channel[];
removeException: (exception: db.Group | db.Channel) => void;
} & ComponentProps<typeof YStack>) {
const insets = useSafeAreaInsets();
return (
<YStack flex={1} {...rest}>
<SizableText
marginHorizontal="$l"
marginBottom="$m"
color="$secondaryText"
>
Exceptions
</SizableText>
<ScrollView flex={1}>
{groups.map((group) => {
return (
<GroupListItem
model={group}
key={group.id}
pressStyle={{ backgroundColor: '$background' }}
customSubtitle={
group.volumeSettings?.level
? ub.NotificationNamesShort[group.volumeSettings.level]
: undefined
}
EndContent={
<ListItem.SystemIcon
icon="Close"
backgroundColor="unset"
onPress={() => removeException(group)}
/>
}
paddingVertical="$s"
/>
);
})}
{channels.map((channel) => {
return (
<ChannelListItem
model={channel}
key={channel.id}
pressStyle={{ backgroundColor: '$background' }}
customSubtitle={
channel.volumeSettings?.level
? ub.NotificationNamesShort[channel.volumeSettings.level]
: undefined
}
EndContent={
<ListItem.SystemIcon
icon="Close"
backgroundColor="unset"
onPress={() => removeException(channel)}
/>
}
paddingVertical="$s"
/>
);
})}
{/* applying padding to the scrollview doesn't work, so use a spacer view */}
<View paddingBottom={insets.bottom} />
</ScrollView>
</YStack>
);
}
90 changes: 59 additions & 31 deletions packages/shared/src/api/activityApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { backOff } from 'exponential-backoff';

import * as db from '../db';
import { createDevLogger, runIfDev } from '../debug';
import { extractClientVolume } from '../logic/activity';
import * as ub from '../urbit';
import {
formatUd,
Expand Down Expand Up @@ -296,22 +295,22 @@ function getInfoFromMessageKey(
return { authorId, postId };
}

export type VolumeUpdate = { sourceId: string; volume: ub.VolumeMap | null };
export type ActivityEvent =
| {
type: 'updateChannelUnread';
activity: db.ChannelUnread;
}
| { type: 'updateThreadUnread'; activity: db.ThreadUnreadState }
| { type: 'updateGroupUnread'; unread: db.GroupUnread }
| {
type: 'updateVolumeSetting';
update: VolumeUpdate;
}
| {
type: 'updateItemVolume';
volumeUpdate: db.VolumeSettings;
}
| {
type: 'removeItemVolume';
itemId: string;
itemType: string;
}
| {
type: 'updatePushNotificationsSetting';
value: ub.PushNotificationsSetting;
Expand Down Expand Up @@ -365,54 +364,83 @@ export function subscribeToActivity(handler: (event: ActivityEvent) => void) {
const { source, volume } = update.adjust;
const sourceId = ub.sourceToString(source);

if ('group' in source) {
const clientVolume = extractClientVolume(volume);
if (sourceId === 'base') {
const level: ub.NotificationLevel = volume
? ub.getLevelFromVolumeMap(volume)
: 'default';
return handler({
type: 'updateItemVolume',
volumeUpdate: {
itemId: source.group,
itemType: 'group',
...clientVolume,
itemId: 'base',
itemType: 'base',
level,
},
});
}

if ('group' in source) {
if (volume) {
return handler({
type: 'updateItemVolume',
volumeUpdate: {
itemId: source.group,
itemType: 'group',
level: ub.getLevelFromVolumeMap(volume),
},
});
} else {
return handler({
type: 'removeItemVolume',
itemId: source.group,
itemType: 'group',
});
}
}

if ('channel' in source || 'dm' in source) {
const clientVolume = extractClientVolume(volume, 'channel' in source);
const channelId =
'channel' in source
? source.channel.nest
: 'ship' in source.dm
? source.dm.ship
: source.dm.club;
return handler({
type: 'updateItemVolume',
volumeUpdate: {
if (volume) {
return handler({
type: 'updateItemVolume',
volumeUpdate: {
itemId: channelId,
itemType: 'channel',
level: ub.getLevelFromVolumeMap(volume),
},
});
} else {
return handler({
type: 'removeItemVolume',
itemId: channelId,
itemType: 'channel',
...clientVolume,
},
});
});
}
}

if ('thread' in source || 'dm-thread' in source) {
const clientVolume = extractClientVolume(volume);
const postId = getPostIdFromSource(source);
return handler({
type: 'updateItemVolume',
volumeUpdate: {
if (volume) {
return handler({
type: 'updateItemVolume',
volumeUpdate: {
itemId: postId,
itemType: 'thread',
level: ub.getLevelFromVolumeMap(volume),
},
});
} else {
return handler({
type: 'removeItemVolume',
itemId: postId,
itemType: 'thread',
...clientVolume,
},
});
});
}
}

// keep handling threads as they were
return handler({
type: 'updateVolumeSetting',
update: { sourceId, volume },
});
}

// handle push notification settings
Expand Down
1 change: 1 addition & 0 deletions packages/shared/src/db/keyValue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const PUSH_NOTIFICATIONS_SETTING_QUERY_KEY = [

export const IS_TLON_EMPLOYEE_QUERY_KEY = ['settings', 'isTlonEmployee'];
export const APP_INFO_QUERY_KEY = ['settings', 'appInfo'];
export const BASE_VOLUME_SETTING_QUERY_KEY = ['volume', 'base'];

export type ChannelSortPreference = 'recency' | 'arranged';
export async function storeChannelSortPreference(
Expand Down
21 changes: 0 additions & 21 deletions packages/shared/src/db/keyValue.web.ts

This file was deleted.

Loading

0 comments on commit ce4e39e

Please sign in to comment.