tangled
alpha
login
or
join now
robinwobin.dev
/
witchsky.app
forked from
jollywhoppers.com/witchsky.app
0
fork
atom
Bluesky app fork with some witchin' additions 💫
0
fork
atom
overview
issues
pulls
pipelines
Merge with upstream for 1.116
xan.lol
1 month ago
83f9cfb5
472772fd
verified
This commit was signed with the committer's
known signature
.
xan.lol
SSH Key Fingerprint:
SHA256:7Zs+dcly5YqxBg7v8XsE1uPMYCobHKBw7CDiNxpmSrY=
+102
-20
5 changed files
expand all
collapse all
unified
split
package.json
src
analytics
metrics
client.ts
features
liveEvents
components
SidebarLiveEventFeedsBanner.tsx
context.tsx
lib
appState.ts
+1
-1
package.json
···
1
{
2
"name": "witchsky-app",
3
-
"version": "1.115.0",
4
"private": true,
5
"engines": {
6
"node": ">=18"
···
1
{
2
"name": "witchsky-app",
3
+
"version": "1.116.0",
4
"private": true,
5
"engines": {
6
"node": ">=18"
+1
-1
src/analytics/metrics/client.ts
···
51
}
52
this.queue.push(e)
53
54
-
logger.info(`event: ${e.event as string}`, e)
55
56
if (this.queue.length > this.maxBatchSize) {
57
this.flush()
···
51
}
52
this.queue.push(e)
53
54
+
logger.debug(`event: ${e.event as string}`, e)
55
56
if (this.queue.length > this.maxBatchSize) {
57
this.flush()
+86
-9
src/features/liveEvents/components/SidebarLiveEventFeedsBanner.tsx
···
0
0
0
0
0
0
0
0
1
import {LiveEventFeedCardCompact} from '#/features/liveEvents/components/LiveEventFeedCardCompact'
2
-
import {useLiveEvents} from '#/features/liveEvents/context'
0
0
3
4
export function SidebarLiveEventFeedsBanner() {
5
-
const events = useLiveEvents()
6
-
return events.feeds.map(feed => (
7
-
<LiveEventFeedCardCompact
8
-
key={feed.id}
9
-
feed={feed}
10
-
metricContext="sidebar"
11
-
/>
12
-
))
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
0
13
}
···
1
+
import {View} from 'react-native'
2
+
import {msg, Trans} from '@lingui/macro'
3
+
import {useLingui} from '@lingui/react'
4
+
5
+
import {atoms as a} from '#/alf'
6
+
import {Button} from '#/components/Button'
7
+
import {TimesLarge_Stroke2_Corner0_Rounded as CloseIcon} from '#/components/icons/Times'
8
+
import * as Toast from '#/components/Toast'
9
import {LiveEventFeedCardCompact} from '#/features/liveEvents/components/LiveEventFeedCardCompact'
10
+
import {useUserPreferencedLiveEvents} from '#/features/liveEvents/context'
11
+
import {useUpdateLiveEventPreferences} from '#/features/liveEvents/preferences'
12
+
import {type LiveEventFeed} from '#/features/liveEvents/types'
13
14
export function SidebarLiveEventFeedsBanner() {
15
+
const events = useUserPreferencedLiveEvents()
16
+
return events.feeds.map(feed => <Inner key={feed.id} feed={feed} />)
17
+
}
18
+
19
+
function Inner({feed}: {feed: LiveEventFeed}) {
20
+
const {_} = useLingui()
21
+
const layout = feed.layouts.wide
22
+
23
+
const {mutate: update, variables} = useUpdateLiveEventPreferences({
24
+
feed,
25
+
metricContext: 'sidebar',
26
+
onUpdateSuccess({undoAction}) {
27
+
Toast.show(
28
+
<Toast.Outer>
29
+
<Toast.Icon />
30
+
<Toast.Text>
31
+
{undoAction ? (
32
+
<Trans>Live event hidden</Trans>
33
+
) : (
34
+
<Trans>Live event unhidden</Trans>
35
+
)}
36
+
</Toast.Text>
37
+
{undoAction && (
38
+
<Toast.Action
39
+
label={_(msg`Undo`)}
40
+
onPress={() => {
41
+
if (undoAction) {
42
+
update(undoAction)
43
+
}
44
+
}}>
45
+
<Trans>Undo</Trans>
46
+
</Toast.Action>
47
+
)}
48
+
</Toast.Outer>,
49
+
{type: 'success'},
50
+
)
51
+
},
52
+
})
53
+
54
+
if (variables) return null
55
+
56
+
return (
57
+
<View style={[a.relative]}>
58
+
<LiveEventFeedCardCompact feed={feed} metricContext="sidebar" />
59
+
60
+
<View
61
+
style={[a.justify_center, a.absolute, {top: 0, right: 6, bottom: 0}]}>
62
+
<Button
63
+
label={_(msg`Dismiss live event banner`)}
64
+
size="tiny"
65
+
shape="round"
66
+
style={[a.z_10]}
67
+
onPress={() => {
68
+
update({type: 'hideFeed', id: feed.id})
69
+
}}>
70
+
{({hovered, pressed}) => (
71
+
<>
72
+
<View
73
+
style={[
74
+
a.absolute,
75
+
a.inset_0,
76
+
a.rounded_full,
77
+
{
78
+
backgroundColor: layout.overlayColor,
79
+
opacity: hovered || pressed ? 0.8 : 0.6,
80
+
},
81
+
]}
82
+
/>
83
+
<CloseIcon size="xs" fill={layout.textColor} style={[a.z_20]} />
84
+
</>
85
+
)}
86
+
</Button>
87
+
</View>
88
+
</View>
89
+
)
90
}
+7
-2
src/features/liveEvents/context.tsx
···
1
import {createContext, useContext, useMemo} from 'react'
2
import {QueryClient, useQuery} from '@tanstack/react-query'
3
0
4
import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam'
5
import {
6
convertBskyAppUrlIfNeeded,
···
35
export function Provider({children}: React.PropsWithChildren<{}>) {
36
const [isDevMode] = useDevMode()
37
const isBskyTeam = useIsBskyTeam()
38
-
const {data} = useQuery(
39
{
40
// keep this, prefectching handles initial load
41
staleTime: 1000 * 15,
42
queryKey: liveEventsQueryKey,
43
-
refetchInterval: 1000 * 60 * 5,
44
async queryFn() {
45
return fetchLiveEvents()
46
},
47
},
48
qc,
49
)
0
0
0
0
50
51
const ctx = useMemo(() => {
52
if (!data) return DEFAULT_LIVE_EVENTS
···
1
import {createContext, useContext, useMemo} from 'react'
2
import {QueryClient, useQuery} from '@tanstack/react-query'
3
4
+
import {useOnAppStateChange} from '#/lib/appState'
5
import {useIsBskyTeam} from '#/lib/hooks/useIsBskyTeam'
6
import {
7
convertBskyAppUrlIfNeeded,
···
36
export function Provider({children}: React.PropsWithChildren<{}>) {
37
const [isDevMode] = useDevMode()
38
const isBskyTeam = useIsBskyTeam()
39
+
const {data, refetch} = useQuery(
40
{
41
// keep this, prefectching handles initial load
42
staleTime: 1000 * 15,
43
queryKey: liveEventsQueryKey,
44
+
refetchInterval: 1000 * 60 * 5, // refetch every 5 minutes
45
async queryFn() {
46
return fetchLiveEvents()
47
},
48
},
49
qc,
50
)
51
+
52
+
useOnAppStateChange(state => {
53
+
if (state === 'active') refetch()
54
+
})
55
56
const ctx = useMemo(() => {
57
if (!data) return DEFAULT_LIVE_EVENTS
+7
-7
src/lib/appState.ts
···
12
})
13
}
14
15
-
export function useAppState() {
16
-
const [state, setState] = useState(AppState.currentState)
17
-
18
useEffect(() => {
19
-
const sub = onAppStateChange(next => {
20
-
setState(next)
21
-
})
22
return () => sub.remove()
23
-
}, [])
0
24
0
0
0
25
return state
26
}
···
12
})
13
}
14
15
+
export function useOnAppStateChange(cb: (state: AppStateStatus) => void) {
0
0
16
useEffect(() => {
17
+
const sub = onAppStateChange(next => cb(next))
0
0
18
return () => sub.remove()
19
+
}, [cb])
20
+
}
21
22
+
export function useAppState() {
23
+
const [state, setState] = useState(AppState.currentState)
24
+
useOnAppStateChange(setState)
25
return state
26
}