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