Remove top padding from shell, move down into individual screens (#5548)

This commit is contained in:
Samuel Newman
2024-10-14 22:09:47 +03:00
committed by GitHub
parent 0f40013963
commit 2d88463453
53 changed files with 1562 additions and 1402 deletions
+13 -13
View File
@@ -17,7 +17,6 @@ import {
import {timeout} from '#/lib/async/timeout' import {timeout} from '#/lib/async/timeout'
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration' import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration'
import {buildStateObject} from '#/lib/routes/helpers' import {buildStateObject} from '#/lib/routes/helpers'
import { import {
@@ -93,6 +92,7 @@ import {
StarterPackScreenShort, StarterPackScreenShort,
} from '#/screens/StarterPack/StarterPackScreen' } from '#/screens/StarterPack/StarterPackScreen'
import {Wizard} from '#/screens/StarterPack/Wizard' import {Wizard} from '#/screens/StarterPack/Wizard'
import {useTheme} from '#/alf'
import {router} from '#/routes' import {router} from '#/routes'
import {Referrer} from '../modules/expo-bluesky-swiss-army' import {Referrer} from '../modules/expo-bluesky-swiss-army'
@@ -412,7 +412,7 @@ function TabsNavigator() {
} }
function HomeTabNavigator() { function HomeTabNavigator() {
const pal = usePalette('default') const t = useTheme()
return ( return (
<HomeTab.Navigator <HomeTab.Navigator
@@ -422,7 +422,7 @@ function HomeTabNavigator() {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<HomeTab.Screen name="Home" getComponent={() => HomeScreen} /> <HomeTab.Screen name="Home" getComponent={() => HomeScreen} />
<HomeTab.Screen name="Start" getComponent={() => HomeScreen} /> <HomeTab.Screen name="Start" getComponent={() => HomeScreen} />
@@ -432,7 +432,7 @@ function HomeTabNavigator() {
} }
function SearchTabNavigator() { function SearchTabNavigator() {
const pal = usePalette('default') const t = useTheme()
return ( return (
<SearchTab.Navigator <SearchTab.Navigator
screenOptions={{ screenOptions={{
@@ -441,7 +441,7 @@ function SearchTabNavigator() {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<SearchTab.Screen name="Search" getComponent={() => SearchScreen} /> <SearchTab.Screen name="Search" getComponent={() => SearchScreen} />
{commonScreens(SearchTab as typeof HomeTab)} {commonScreens(SearchTab as typeof HomeTab)}
@@ -450,7 +450,7 @@ function SearchTabNavigator() {
} }
function NotificationsTabNavigator() { function NotificationsTabNavigator() {
const pal = usePalette('default') const t = useTheme()
return ( return (
<NotificationsTab.Navigator <NotificationsTab.Navigator
screenOptions={{ screenOptions={{
@@ -459,7 +459,7 @@ function NotificationsTabNavigator() {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<NotificationsTab.Screen <NotificationsTab.Screen
name="Notifications" name="Notifications"
@@ -472,7 +472,7 @@ function NotificationsTabNavigator() {
} }
function MyProfileTabNavigator() { function MyProfileTabNavigator() {
const pal = usePalette('default') const t = useTheme()
return ( return (
<MyProfileTab.Navigator <MyProfileTab.Navigator
screenOptions={{ screenOptions={{
@@ -481,7 +481,7 @@ function MyProfileTabNavigator() {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<MyProfileTab.Screen <MyProfileTab.Screen
// @ts-ignore // TODO: fix this broken type in ProfileScreen // @ts-ignore // TODO: fix this broken type in ProfileScreen
@@ -498,7 +498,7 @@ function MyProfileTabNavigator() {
} }
function MessagesTabNavigator() { function MessagesTabNavigator() {
const pal = usePalette('default') const t = useTheme()
return ( return (
<MessagesTab.Navigator <MessagesTab.Navigator
screenOptions={{ screenOptions={{
@@ -507,7 +507,7 @@ function MessagesTabNavigator() {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<MessagesTab.Screen <MessagesTab.Screen
name="Messages" name="Messages"
@@ -527,7 +527,7 @@ function MessagesTabNavigator() {
* in a single ("flat") stack. * in a single ("flat") stack.
*/ */
const FlatNavigator = () => { const FlatNavigator = () => {
const pal = usePalette('default') const t = useTheme()
const numUnread = useUnreadNotifications() const numUnread = useUnreadNotifications()
const screenListeners = useWebScrollRestoration() const screenListeners = useWebScrollRestoration()
const title = (page: MessageDescriptor) => bskyTitle(i18n._(page), numUnread) const title = (page: MessageDescriptor) => bskyTitle(i18n._(page), numUnread)
@@ -541,7 +541,7 @@ const FlatNavigator = () => {
gestureEnabled: true, gestureEnabled: true,
fullScreenGestureEnabled: true, fullScreenGestureEnabled: true,
headerShown: false, headerShown: false,
contentStyle: pal.view, contentStyle: t.atoms.bg,
}}> }}>
<Flat.Screen <Flat.Screen
name="Home" name="Home"
+41
View File
@@ -0,0 +1,41 @@
import React from 'react'
import {View, ViewStyle} from 'react-native'
import {StyleProp} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {atoms as a} from '#/alf'
// Every screen should have a Layout component wrapping it.
// This component provides a default padding for the top of the screen.
// This allows certain screens to avoid the top padding if they want to.
//
// In a future PR I will add a unified header component to this file and
// things like a preconfigured scrollview.
/**
* Every screen should have a Layout.Screen component wrapping it.
* This component provides a default padding for the top of the screen
* and height/minHeight
*/
let Screen = ({
disableTopPadding,
style,
...props
}: React.ComponentProps<typeof View> & {
disableTopPadding?: boolean
style?: StyleProp<ViewStyle>
}): React.ReactNode => {
const {top} = useSafeAreaInsets()
return (
<View
style={[
{paddingTop: disableTopPadding ? 0 : top},
a.util_screen_outer,
style,
]}
{...props}
/>
)
}
Screen = React.memo(Screen)
export {Screen}
+101 -98
View File
@@ -1,9 +1,10 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {ScrollView} from 'view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import {Button, ButtonText} from '#/components/Button' import {Button, ButtonText} from '#/components/Button'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {SharedPrefs} from '../../../modules/expo-bluesky-swiss-army' import {SharedPrefs} from '../../../modules/expo-bluesky-swiss-army'
@@ -11,103 +12,105 @@ export function SharedPreferencesTesterScreen() {
const [currentTestOutput, setCurrentTestOutput] = React.useState<string>('') const [currentTestOutput, setCurrentTestOutput] = React.useState<string>('')
return ( return (
<ScrollView contentContainerStyle={{backgroundColor: 'red'}}> <Layout.Screen>
<View style={[a.flex_1]}> <ScrollView contentContainerStyle={{backgroundColor: 'red'}}>
<View> <View style={[a.flex_1]}>
<Text testID="testOutput">{currentTestOutput}</Text> <View>
<Text testID="testOutput">{currentTestOutput}</Text>
</View>
<View style={[a.flex_wrap]}>
<Button
label="btn"
testID="setStringBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerString')
SharedPrefs.setValue('testerString', 'Hello')
const str = SharedPrefs.getString('testerString')
console.log(JSON.stringify(str))
setCurrentTestOutput(`${str}`)
}}>
<ButtonText>Set String</ButtonText>
</Button>
<Button
label="btn"
testID="removeStringBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerString')
const str = SharedPrefs.getString('testerString')
setCurrentTestOutput(`${str}`)
}}>
<ButtonText>Remove String</ButtonText>
</Button>
<Button
label="btn"
testID="setBoolBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerBool')
SharedPrefs.setValue('testerBool', true)
const bool = SharedPrefs.getBool('testerBool')
setCurrentTestOutput(`${bool}`)
}}>
<ButtonText>Set Bool</ButtonText>
</Button>
<Button
label="btn"
testID="setNumberBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerNumber')
SharedPrefs.setValue('testerNumber', 123)
const num = SharedPrefs.getNumber('testerNumber')
setCurrentTestOutput(`${num}`)
}}>
<ButtonText>Set Number</ButtonText>
</Button>
<Button
label="btn"
testID="addToSetBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeFromSet('testerSet', 'Hello!')
SharedPrefs.addToSet('testerSet', 'Hello!')
const contains = SharedPrefs.setContains('testerSet', 'Hello!')
setCurrentTestOutput(`${contains}`)
}}>
<ButtonText>Add to Set</ButtonText>
</Button>
<Button
label="btn"
testID="removeFromSetBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeFromSet('testerSet', 'Hello!')
const contains = SharedPrefs.setContains('testerSet', 'Hello!')
setCurrentTestOutput(`${contains}`)
}}>
<ButtonText>Remove from Set</ButtonText>
</Button>
</View>
</View> </View>
<View style={[a.flex_wrap]}> </ScrollView>
<Button </Layout.Screen>
label="btn"
testID="setStringBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerString')
SharedPrefs.setValue('testerString', 'Hello')
const str = SharedPrefs.getString('testerString')
console.log(JSON.stringify(str))
setCurrentTestOutput(`${str}`)
}}>
<ButtonText>Set String</ButtonText>
</Button>
<Button
label="btn"
testID="removeStringBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerString')
const str = SharedPrefs.getString('testerString')
setCurrentTestOutput(`${str}`)
}}>
<ButtonText>Remove String</ButtonText>
</Button>
<Button
label="btn"
testID="setBoolBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerBool')
SharedPrefs.setValue('testerBool', true)
const bool = SharedPrefs.getBool('testerBool')
setCurrentTestOutput(`${bool}`)
}}>
<ButtonText>Set Bool</ButtonText>
</Button>
<Button
label="btn"
testID="setNumberBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeValue('testerNumber')
SharedPrefs.setValue('testerNumber', 123)
const num = SharedPrefs.getNumber('testerNumber')
setCurrentTestOutput(`${num}`)
}}>
<ButtonText>Set Number</ButtonText>
</Button>
<Button
label="btn"
testID="addToSetBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeFromSet('testerSet', 'Hello!')
SharedPrefs.addToSet('testerSet', 'Hello!')
const contains = SharedPrefs.setContains('testerSet', 'Hello!')
setCurrentTestOutput(`${contains}`)
}}>
<ButtonText>Add to Set</ButtonText>
</Button>
<Button
label="btn"
testID="removeFromSetBtn"
style={[a.self_center]}
variant="solid"
color="primary"
size="small"
onPress={async () => {
SharedPrefs.removeFromSet('testerSet', 'Hello!')
const contains = SharedPrefs.setContains('testerSet', 'Hello!')
setCurrentTestOutput(`${contains}`)
}}>
<ButtonText>Remove from Set</ButtonText>
</Button>
</View>
</View>
</ScrollView>
) )
} }
+16 -15
View File
@@ -6,23 +6,24 @@ import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {HITSLOP_10} from 'lib/constants' import {HITSLOP_10} from '#/lib/constants'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams} from 'lib/routes/types' import {CommonNavigatorParams} from '#/lib/routes/types'
import {shareUrl} from 'lib/sharing' import {shareUrl} from '#/lib/sharing'
import {cleanError} from 'lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from '#/lib/strings/handles'
import {enforceLen} from 'lib/strings/helpers' import {enforceLen} from '#/lib/strings/helpers'
import {isNative, isWeb} from 'platform/detection' import {isNative, isWeb} from '#/platform/detection'
import {useSearchPostsQuery} from 'state/queries/search-posts' import {useSearchPostsQuery} from '#/state/queries/search-posts'
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from 'state/shell' import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
import {Pager} from '#/view/com/pager/Pager' import {Pager} from '#/view/com/pager/Pager'
import {TabBar} from '#/view/com/pager/TabBar' import {TabBar} from '#/view/com/pager/TabBar'
import {Post} from '#/view/com/post/Post'
import {List} from '#/view/com/util/List'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {Post} from 'view/com/post/Post'
import {List} from 'view/com/util/List'
import {ViewHeader} from 'view/com/util/ViewHeader'
import {ArrowOutOfBox_Stroke2_Corner0_Rounded} from '#/components/icons/ArrowOutOfBox' import {ArrowOutOfBox_Stroke2_Corner0_Rounded} from '#/components/icons/ArrowOutOfBox'
import * as Layout from '#/components/Layout'
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
const renderItem = ({item}: ListRenderItemInfo<PostView>) => { const renderItem = ({item}: ListRenderItemInfo<PostView>) => {
@@ -108,7 +109,7 @@ export default function HashtagScreen({
}, [_, fullTag, author, activeTab]) }, [_, fullTag, author, activeTab])
return ( return (
<> <Layout.Screen>
<CenteredView sideBorders={true}> <CenteredView sideBorders={true}>
<ViewHeader <ViewHeader
showOnDesktop showOnDesktop
@@ -155,7 +156,7 @@ export default function HashtagScreen({
<View key={i}>{section.component}</View> <View key={i}>{section.component}</View>
))} ))}
</Pager> </Pager>
</> </Layout.Screen>
) )
} }
+5 -4
View File
@@ -28,6 +28,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico
import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message' import {Message_Stroke2_Corner0_Rounded as Message} from '#/components/icons/Message'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider' import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link' import {Link} from '#/components/Link'
import {ListFooter} from '#/components/Lists' import {ListFooter} from '#/components/Lists'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
@@ -149,7 +150,7 @@ export function MessagesScreen({navigation, route}: Props) {
if (conversations.length < 1) { if (conversations.length < 1) {
return ( return (
<View style={a.flex_1}> <Layout.Screen>
<CenteredView sideBorders={gtMobile} style={[a.h_full_vh]}> <CenteredView sideBorders={gtMobile} style={[a.h_full_vh]}>
{gtMobile ? ( {gtMobile ? (
<DesktopHeader <DesktopHeader
@@ -231,12 +232,12 @@ export function MessagesScreen({navigation, route}: Props) {
{!isLoading && !isError && ( {!isLoading && !isError && (
<NewChat onNewChat={onNewChat} control={newChatControl} /> <NewChat onNewChat={onNewChat} control={newChatControl} />
)} )}
</View> </Layout.Screen>
) )
} }
return ( return (
<View style={a.flex_1}> <Layout.Screen testID="messagesScreen">
{!gtMobile && ( {!gtMobile && (
<ViewHeader <ViewHeader
title={_(msg`Messages`)} title={_(msg`Messages`)}
@@ -276,7 +277,7 @@ export function MessagesScreen({navigation, route}: Props) {
// @ts-ignore our .web version only -sfn // @ts-ignore our .web version only -sfn
desktopFixedHeight desktopFixedHeight
/> />
</View> </Layout.Screen>
) )
} }
+8 -5
View File
@@ -18,10 +18,11 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {MessagesList} from '#/screens/Messages/components/MessagesList' import {MessagesList} from '#/screens/Messages/components/MessagesList'
import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter' import {MessagesListBlockedFooter} from '#/components/dms/MessagesListBlockedFooter'
import {MessagesListHeader} from '#/components/dms/MessagesListHeader' import {MessagesListHeader} from '#/components/dms/MessagesListHeader'
import {Error} from '#/components/Error' import {Error} from '#/components/Error'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
@@ -64,9 +65,11 @@ export function MessagesConversationScreen({route}: Props) {
) )
return ( return (
<ConvoProvider key={convoId} convoId={convoId}> <Layout.Screen testID="convoScreen" style={web([{minHeight: 0}, a.flex_1])}>
<Inner /> <ConvoProvider key={convoId} convoId={convoId}>
</ConvoProvider> <Inner />
</ConvoProvider>
</Layout.Screen>
) )
} }
@@ -100,7 +103,7 @@ function Inner() {
if (convoState.status === ConvoStatus.Error) { if (convoState.status === ConvoStatus.Error) {
return ( return (
<CenteredView style={a.flex_1} sideBorders> <CenteredView style={[a.flex_1]} sideBorders>
<MessagesListHeader /> <MessagesListHeader />
<Error <Error
title={_(msg`Something went wrong`)} title={_(msg`Something went wrong`)}
+89 -86
View File
@@ -16,6 +16,7 @@ import {atoms as a} from '#/alf'
import {Admonition} from '#/components/Admonition' import {Admonition} from '#/components/Admonition'
import {Divider} from '#/components/Divider' import {Divider} from '#/components/Divider'
import * as Toggle from '#/components/forms/Toggle' import * as Toggle from '#/components/forms/Toggle'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider' import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
@@ -55,91 +56,93 @@ export function MessagesSettingsScreen({}: Props) {
) )
return ( return (
<ScrollView stickyHeaderIndices={[0]}> <Layout.Screen testID="messagesSettingsScreen">
<ViewHeader title={_(msg`Chat Settings`)} showOnDesktop showBorder /> <ScrollView stickyHeaderIndices={[0]}>
<View style={[a.p_lg, a.gap_md]}> <ViewHeader title={_(msg`Chat Settings`)} showOnDesktop showBorder />
<Text style={[a.text_lg, a.font_bold]}> <View style={[a.p_lg, a.gap_md]}>
<Trans>Allow new messages from</Trans> <Text style={[a.text_lg, a.font_bold]}>
</Text> <Trans>Allow new messages from</Trans>
<Toggle.Group </Text>
label={_(msg`Allow new messages from`)} <Toggle.Group
type="radio" label={_(msg`Allow new messages from`)}
values={[ type="radio"
(profile?.associated?.chat?.allowIncoming as AllowIncoming) ?? values={[
'following', (profile?.associated?.chat?.allowIncoming as AllowIncoming) ??
]} 'following',
onChange={onSelectMessagesFrom}> ]}
<View> onChange={onSelectMessagesFrom}>
<Toggle.Item <View>
name="all" <Toggle.Item
label={_(msg`Everyone`)} name="all"
style={[a.justify_between, a.py_sm]}> label={_(msg`Everyone`)}
<Toggle.LabelText> style={[a.justify_between, a.py_sm]}>
<Trans>Everyone</Trans> <Toggle.LabelText>
</Toggle.LabelText> <Trans>Everyone</Trans>
<Toggle.Radio /> </Toggle.LabelText>
</Toggle.Item> <Toggle.Radio />
<Toggle.Item </Toggle.Item>
name="following" <Toggle.Item
label={_(msg`Users I follow`)} name="following"
style={[a.justify_between, a.py_sm]}> label={_(msg`Users I follow`)}
<Toggle.LabelText> style={[a.justify_between, a.py_sm]}>
<Trans>Users I follow</Trans> <Toggle.LabelText>
</Toggle.LabelText> <Trans>Users I follow</Trans>
<Toggle.Radio /> </Toggle.LabelText>
</Toggle.Item> <Toggle.Radio />
<Toggle.Item </Toggle.Item>
name="none" <Toggle.Item
label={_(msg`No one`)} name="none"
style={[a.justify_between, a.py_sm]}> label={_(msg`No one`)}
<Toggle.LabelText> style={[a.justify_between, a.py_sm]}>
<Trans>No one</Trans> <Toggle.LabelText>
</Toggle.LabelText> <Trans>No one</Trans>
<Toggle.Radio /> </Toggle.LabelText>
</Toggle.Item> <Toggle.Radio />
</View> </Toggle.Item>
</Toggle.Group> </View>
<Admonition type="tip"> </Toggle.Group>
<Trans> <Admonition type="tip">
You can continue ongoing conversations regardless of which setting <Trans>
you choose. You can continue ongoing conversations regardless of which setting
</Trans> you choose.
</Admonition> </Trans>
{isNative && ( </Admonition>
<> {isNative && (
<Divider style={a.my_md} /> <>
<Text style={[a.text_lg, a.font_bold]}> <Divider style={a.my_md} />
<Trans>Notification Sounds</Trans> <Text style={[a.text_lg, a.font_bold]}>
</Text> <Trans>Notification Sounds</Trans>
<Toggle.Group </Text>
label={_(msg`Notification sounds`)} <Toggle.Group
type="radio" label={_(msg`Notification sounds`)}
values={[preferences.playSoundChat ? 'enabled' : 'disabled']} type="radio"
onChange={onSelectSoundSetting}> values={[preferences.playSoundChat ? 'enabled' : 'disabled']}
<View> onChange={onSelectSoundSetting}>
<Toggle.Item <View>
name="enabled" <Toggle.Item
label={_(msg`Enabled`)} name="enabled"
style={[a.justify_between, a.py_sm]}> label={_(msg`Enabled`)}
<Toggle.LabelText> style={[a.justify_between, a.py_sm]}>
<Trans>Enabled</Trans> <Toggle.LabelText>
</Toggle.LabelText> <Trans>Enabled</Trans>
<Toggle.Radio /> </Toggle.LabelText>
</Toggle.Item> <Toggle.Radio />
<Toggle.Item </Toggle.Item>
name="disabled" <Toggle.Item
label={_(msg`Disabled`)} name="disabled"
style={[a.justify_between, a.py_sm]}> label={_(msg`Disabled`)}
<Toggle.LabelText> style={[a.justify_between, a.py_sm]}>
<Trans>Disabled</Trans> <Toggle.LabelText>
</Toggle.LabelText> <Trans>Disabled</Trans>
<Toggle.Radio /> </Toggle.LabelText>
</Toggle.Item> <Toggle.Radio />
</View> </Toggle.Item>
</Toggle.Group> </View>
</> </Toggle.Group>
)} </>
</View> )}
</ScrollView> </View>
</ScrollView>
</Layout.Screen>
) )
} }
+27 -24
View File
@@ -41,6 +41,7 @@ import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filte
import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group' import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group'
import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person'
import * as LabelingService from '#/components/LabelingServiceCard' import * as LabelingService from '#/components/LabelingServiceCard'
import * as Layout from '#/components/Layout'
import {InlineLinkText, Link} from '#/components/Link' import {InlineLinkText, Link} from '#/components/Link'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {GlobalLabelPreference} from '#/components/moderation/LabelPreference' import {GlobalLabelPreference} from '#/components/moderation/LabelPreference'
@@ -94,31 +95,33 @@ export function ModerationScreen(
const error = preferencesError const error = preferencesError
return ( return (
<CenteredView <Layout.Screen testID="moderationScreen">
testID="moderationScreen" <CenteredView
style={[ testID="moderationScreen"
t.atoms.border_contrast_low, style={[
t.atoms.bg, t.atoms.border_contrast_low,
{minHeight: height}, t.atoms.bg,
...(gtMobile ? [a.border_l, a.border_r] : []), {minHeight: height},
]}> ...(gtMobile ? [a.border_l, a.border_r] : []),
<ViewHeader title={_(msg`Moderation`)} showOnDesktop /> ]}>
<ViewHeader title={_(msg`Moderation`)} showOnDesktop />
{isLoading ? ( {isLoading ? (
<View style={[a.w_full, a.align_center, a.pt_2xl]}> <View style={[a.w_full, a.align_center, a.pt_2xl]}>
<Loader size="xl" fill={t.atoms.text.color} /> <Loader size="xl" fill={t.atoms.text.color} />
</View> </View>
) : error || !preferences ? ( ) : error || !preferences ? (
<ErrorState <ErrorState
error={ error={
preferencesError?.toString() || preferencesError?.toString() ||
_(msg`Something went wrong, please try again.`) _(msg`Something went wrong, please try again.`)
} }
/> />
) : ( ) : (
<ModerationScreenInner preferences={preferences} /> <ModerationScreenInner preferences={preferences} />
)} )}
</CenteredView> </CenteredView>
</Layout.Screen>
) )
} }
+10 -8
View File
@@ -5,12 +5,12 @@ import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers' import {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy' import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists' import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
@@ -27,10 +27,12 @@ export const PostLikedByScreen = ({route}: Props) => {
) )
return ( return (
<CenteredView style={a.util_screen_outer} sideBorders={true}> <Layout.Screen>
<ListHeaderDesktop title={_(msg`Liked By`)} /> <CenteredView sideBorders={true}>
<ViewHeader title={_(msg`Liked By`)} showBorder={!isWeb} /> <ListHeaderDesktop title={_(msg`Liked By`)} />
<PostLikedByComponent uri={uri} /> <ViewHeader title={_(msg`Liked By`)} showBorder={!isWeb} />
</CenteredView> <PostLikedByComponent uri={uri} />
</CenteredView>
</Layout.Screen>
) )
} }
+10 -8
View File
@@ -5,12 +5,12 @@ import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers' import {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostQuotes as PostQuotesComponent} from '#/view/com/post-thread/PostQuotes' import {PostQuotes as PostQuotesComponent} from '#/view/com/post-thread/PostQuotes'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists' import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostQuotes'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostQuotes'>
@@ -27,10 +27,12 @@ export const PostQuotesScreen = ({route}: Props) => {
) )
return ( return (
<CenteredView style={a.util_screen_outer} sideBorders={true}> <Layout.Screen>
<ListHeaderDesktop title={_(msg`Quotes`)} /> <CenteredView sideBorders={true}>
<ViewHeader title={_(msg`Quotes`)} showBorder={!isWeb} /> <ListHeaderDesktop title={_(msg`Quotes`)} />
<PostQuotesComponent uri={uri} /> <ViewHeader title={_(msg`Quotes`)} showBorder={!isWeb} />
</CenteredView> <PostQuotesComponent uri={uri} />
</CenteredView>
</Layout.Screen>
) )
} }
+10 -8
View File
@@ -5,12 +5,12 @@ import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers' import {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostRepostedBy as PostRepostedByComponent} from '#/view/com/post-thread/PostRepostedBy' import {PostRepostedBy as PostRepostedByComponent} from '#/view/com/post-thread/PostRepostedBy'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists' import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
@@ -27,10 +27,12 @@ export const PostRepostedByScreen = ({route}: Props) => {
) )
return ( return (
<CenteredView style={a.util_screen_outer} sideBorders={true}> <Layout.Screen>
<ListHeaderDesktop title={_(msg`Reposted By`)} /> <CenteredView sideBorders={true}>
<ViewHeader title={_(msg`Reposted By`)} showBorder={!isWeb} /> <ListHeaderDesktop title={_(msg`Reposted By`)} />
<PostRepostedByComponent uri={uri} /> <ViewHeader title={_(msg`Reposted By`)} showBorder={!isWeb} />
</CenteredView> <PostRepostedByComponent uri={uri} />
</CenteredView>
</Layout.Screen>
) )
} }
+15 -13
View File
@@ -1,20 +1,20 @@
import React from 'react' import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api' import {AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {cleanError} from '#/lib/strings/errors' import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger' import {logger} from '#/logger'
import {useProfileKnownFollowersQuery} from '#/state/queries/known-followers' import {useProfileKnownFollowersQuery} from '#/state/queries/known-followers'
import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {useResolveDidQuery} from '#/state/queries/resolve-uri'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard' import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
import {List} from '#/view/com/util/List' import {List} from '#/view/com/util/List'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
import { import {
ListFooter, ListFooter,
ListHeaderDesktop, ListHeaderDesktop,
@@ -92,19 +92,21 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
if (followers.length < 1) { if (followers.length < 1) {
return ( return (
<ListMaybePlaceholder <Layout.Screen>
isLoading={isDidLoading || isFollowersLoading} <ListMaybePlaceholder
isError={isError} isLoading={isDidLoading || isFollowersLoading}
emptyType="results" isError={isError}
emptyMessage={_(msg`You don't follow any users who follow @${name}.`)} emptyType="results"
errorMessage={cleanError(resolveError || error)} emptyMessage={_(msg`You don't follow any users who follow @${name}.`)}
onRetry={isError ? refetch : undefined} errorMessage={cleanError(resolveError || error)}
/> onRetry={isError ? refetch : undefined}
/>
</Layout.Screen>
) )
} }
return ( return (
<View style={{flex: 1}}> <Layout.Screen>
<ViewHeader title={_(msg`Followers you know`)} /> <ViewHeader title={_(msg`Followers you know`)} />
<List <List
data={followers} data={followers}
@@ -129,6 +131,6 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
initialNumToRender={initialNumToRender} initialNumToRender={initialNumToRender}
windowSize={11} windowSize={11}
/> />
</View> </Layout.Screen>
) )
} }
@@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import {View} from 'react-native'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
@@ -8,6 +7,7 @@ import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers' import {makeRecordUri} from '#/lib/strings/url-helpers'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
import {LikedByList} from '#/components/LikedByList' import {LikedByList} from '#/components/LikedByList'
export function ProfileLabelerLikedByScreen({ export function ProfileLabelerLikedByScreen({
@@ -25,9 +25,9 @@ export function ProfileLabelerLikedByScreen({
) )
return ( return (
<View style={{flex: 1}}> <Layout.Screen>
<ViewHeader title={_(msg`Liked By`)} /> <ViewHeader title={_(msg`Liked By`)} />
<LikedByList uri={uri} /> <LikedByList uri={uri} />
</View> </Layout.Screen>
) )
} }
+3 -3
View File
@@ -10,7 +10,6 @@ import {useLingui} from '@lingui/react'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetThemePrefs, useThemePrefs} from '#/state/shell' import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {ScrollView} from '#/view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
@@ -21,6 +20,7 @@ import {Moon_Stroke2_Corner0_Rounded as MoonIcon} from '#/components/icons/Moon'
import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone' import {Phone_Stroke2_Corner0_Rounded as PhoneIcon} from '#/components/icons/Phone'
import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize' import {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase' import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'>
@@ -76,7 +76,7 @@ export function AppearanceSettingsScreen({}: Props) {
return ( return (
<LayoutAnimationConfig skipExiting skipEntering> <LayoutAnimationConfig skipExiting skipEntering>
<View testID="preferencesThreadsScreen" style={s.hContentRegion}> <Layout.Screen testID="preferencesThreadsScreen">
<ScrollView <ScrollView
// @ts-ignore web only -prf // @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}} dataSet={{'stable-gutters': 1}}
@@ -180,7 +180,7 @@ export function AppearanceSettingsScreen({}: Props) {
</View> </View>
</View> </View>
</ScrollView> </ScrollView>
</View> </Layout.Screen>
</LayoutAnimationConfig> </LayoutAnimationConfig>
) )
} }
+19 -8
View File
@@ -53,6 +53,7 @@ import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/ico
import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid' import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid'
import {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil' import {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import * as Layout from '#/components/Layout'
import {ListMaybePlaceholder} from '#/components/Lists' import {ListMaybePlaceholder} from '#/components/Lists'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import * as Menu from '#/components/Menu' import * as Menu from '#/components/Menu'
@@ -76,7 +77,11 @@ type StarterPackScreenShortProps = NativeStackScreenProps<
> >
export function StarterPackScreen({route}: StarterPackScreeProps) { export function StarterPackScreen({route}: StarterPackScreeProps) {
return <StarterPackScreenInner routeParams={route.params} /> return (
<Layout.Screen>
<StarterPackScreenInner routeParams={route.params} />
</Layout.Screen>
)
} }
export function StarterPackScreenShort({route}: StarterPackScreenShortProps) { export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
@@ -91,15 +96,21 @@ export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
if (isLoading || isError || !resolvedStarterPack) { if (isLoading || isError || !resolvedStarterPack) {
return ( return (
<ListMaybePlaceholder <Layout.Screen>
isLoading={isLoading} <ListMaybePlaceholder
isError={isError} isLoading={isLoading}
errorMessage={_(msg`That starter pack could not be found.`)} isError={isError}
emptyMessage={_(msg`That starter pack could not be found.`)} errorMessage={_(msg`That starter pack could not be found.`)}
/> emptyMessage={_(msg`That starter pack could not be found.`)}
/>
</Layout.Screen>
) )
} }
return <StarterPackScreenInner routeParams={resolvedStarterPack} /> return (
<Layout.Screen>
<StarterPackScreenInner routeParams={resolvedStarterPack} />
</Layout.Screen>
)
} }
export function StarterPackScreenInner({ export function StarterPackScreenInner({
+45 -38
View File
@@ -19,32 +19,32 @@ import {useLingui} from '@lingui/react'
import {useFocusEffect, useNavigation} from '@react-navigation/native' import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack' import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {logger} from '#/logger' import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from 'lib/constants' import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {createSanitizedDisplayName} from 'lib/moderation/create-sanitized-display-name' import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types' import {logEvent} from '#/lib/statsig/statsig'
import {logEvent} from 'lib/statsig/statsig' import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from '#/lib/strings/handles'
import {sanitizeHandle} from 'lib/strings/handles' import {enforceLen} from '#/lib/strings/helpers'
import {enforceLen} from 'lib/strings/helpers'
import { import {
getStarterPackOgCard, getStarterPackOgCard,
parseStarterPackUri, parseStarterPackUri,
} from 'lib/strings/starter-pack' } from '#/lib/strings/starter-pack'
import {isAndroid, isNative, isWeb} from 'platform/detection' import {logger} from '#/logger'
import {useModerationOpts} from 'state/preferences/moderation-opts' import {isAndroid, isNative, isWeb} from '#/platform/detection'
import {useAllListMembersQuery} from 'state/queries/list-members' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useProfileQuery} from 'state/queries/profile' import {useAllListMembersQuery} from '#/state/queries/list-members'
import {useProfileQuery} from '#/state/queries/profile'
import { import {
useCreateStarterPackMutation, useCreateStarterPackMutation,
useEditStarterPackMutation, useEditStarterPackMutation,
useStarterPackQuery, useStarterPackQuery,
} from 'state/queries/starter-packs' } from '#/state/queries/starter-packs'
import {useSession} from 'state/session' import {useSession} from '#/state/session'
import {useSetMinimalShellMode} from 'state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import * as Toast from '#/view/com/util/Toast' import * as Toast from '#/view/com/util/Toast'
import {UserAvatar} from 'view/com/util/UserAvatar' import {UserAvatar} from '#/view/com/util/UserAvatar'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {useWizardState, WizardStep} from '#/screens/StarterPack/Wizard/State' import {useWizardState, WizardStep} from '#/screens/StarterPack/Wizard/State'
import {StepDetails} from '#/screens/StarterPack/Wizard/StepDetails' import {StepDetails} from '#/screens/StarterPack/Wizard/StepDetails'
import {StepFeeds} from '#/screens/StarterPack/Wizard/StepFeeds' import {StepFeeds} from '#/screens/StarterPack/Wizard/StepFeeds'
@@ -52,6 +52,7 @@ import {StepProfiles} from '#/screens/StarterPack/Wizard/StepProfiles'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button' import {Button, ButtonText} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import {ListMaybePlaceholder} from '#/components/Lists' import {ListMaybePlaceholder} from '#/components/Lists'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {WizardEditListDialog} from '#/components/StarterPack/Wizard/WizardEditListDialog' import {WizardEditListDialog} from '#/components/StarterPack/Wizard/WizardEditListDialog'
@@ -97,33 +98,39 @@ export function Wizard({
if (!isReady) { if (!isReady) {
return ( return (
<ListMaybePlaceholder <Layout.Screen>
isLoading={ <ListMaybePlaceholder
isLoadingStarterPack || isLoadingProfiles || isLoadingProfile isLoading={
} isLoadingStarterPack || isLoadingProfiles || isLoadingProfile
isError={isErrorStarterPack || isErrorProfiles || isErrorProfile} }
errorMessage={_(msg`That starter pack could not be found.`)} isError={isErrorStarterPack || isErrorProfiles || isErrorProfile}
/> errorMessage={_(msg`That starter pack could not be found.`)}
/>
</Layout.Screen>
) )
} else if (isEdit && starterPack?.creator.did !== currentAccount?.did) { } else if (isEdit && starterPack?.creator.did !== currentAccount?.did) {
return ( return (
<ListMaybePlaceholder <Layout.Screen>
isLoading={false} <ListMaybePlaceholder
isError={true} isLoading={false}
errorMessage={_(msg`That starter pack could not be found.`)} isError={true}
/> errorMessage={_(msg`That starter pack could not be found.`)}
/>
</Layout.Screen>
) )
} }
return ( return (
<Provider starterPack={starterPack} listItems={listItems}> <Layout.Screen>
<WizardInner <Provider starterPack={starterPack} listItems={listItems}>
currentStarterPack={starterPack} <WizardInner
currentListItems={listItems} currentStarterPack={starterPack}
profile={profile} currentListItems={listItems}
moderationOpts={moderationOpts} profile={profile}
/> moderationOpts={moderationOpts}
</Provider> />
</Provider>
</Layout.Screen>
) )
} }
+3 -2
View File
@@ -27,6 +27,7 @@ import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -54,7 +55,7 @@ export function AccessibilitySettingsScreen({}: Props) {
) )
return ( return (
<View style={s.hContentRegion} testID="accessibilitySettingsScreen"> <Layout.Screen testID="accessibilitySettingsScreen">
<SimpleViewHeader <SimpleViewHeader
showBackButton={isTabletOrMobile} showBackButton={isTabletOrMobile}
style={[ style={[
@@ -128,7 +129,7 @@ export function AccessibilitySettingsScreen({}: Props) {
</> </>
)} )}
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+9
View File
@@ -30,10 +30,19 @@ import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
export function AppPasswords({}: Props) { export function AppPasswords({}: Props) {
return (
<Layout.Screen testID="AppPasswordsScreen">
<AppPasswordsInner />
</Layout.Screen>
)
}
function AppPasswordsInner() {
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {msg, Trans} from '@lingui/macro'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from 'view/com/util/Link'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from 'view/com/util/Views'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {TextLink} from '#/view/com/util/Link'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -28,7 +30,7 @@ export const CommunityGuidelinesScreen = (_props: Props) => {
) )
return ( return (
<View> <Layout.Screen>
<ViewHeader title={_(msg`Community Guidelines`)} /> <ViewHeader title={_(msg`Community Guidelines`)} />
<ScrollView style={[s.hContentRegion, pal.view]}> <ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}> <View style={[s.p20]}>
@@ -45,6 +47,6 @@ export const CommunityGuidelinesScreen = (_props: Props) => {
</View> </View>
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {msg, Trans} from '@lingui/macro'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from 'view/com/util/Link'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from 'view/com/util/Views'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {TextLink} from '#/view/com/util/Link'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'CopyrightPolicy'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'CopyrightPolicy'>
export const CopyrightPolicyScreen = (_props: Props) => { export const CopyrightPolicyScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const CopyrightPolicyScreen = (_props: Props) => {
) )
return ( return (
<View> <Layout.Screen>
<ViewHeader title={_(msg`Copyright Policy`)} /> <ViewHeader title={_(msg`Copyright Policy`)} />
<ScrollView style={[s.hContentRegion, pal.view]}> <ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}> <View style={[s.p20]}>
@@ -42,6 +44,6 @@ export const CopyrightPolicyScreen = (_props: Props) => {
</View> </View>
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+27 -20
View File
@@ -1,24 +1,29 @@
import React from 'react' import React from 'react'
import {ScrollView, View} from 'react-native' import {ScrollView, View} from 'react-native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {ThemeProvider, PaletteColorName} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import * as Toast from 'view/com/util/Toast'
import {Text} from '../com/util/text/Text'
import {ViewSelector} from '../com/util/ViewSelector'
import {EmptyState} from '../com/util/EmptyState'
import * as LoadingPlaceholder from '../com/util/LoadingPlaceholder'
import {Button, ButtonType} from '../com/util/forms/Button'
import {DropdownButton, DropdownItem} from '../com/util/forms/DropdownButton'
import {ToggleButton} from '../com/util/forms/ToggleButton'
import {RadioGroup} from '../com/util/forms/RadioGroup'
import {ErrorScreen} from '../com/util/error/ErrorScreen'
import {ErrorMessage} from '../com/util/error/ErrorMessage'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {PaletteColorName, ThemeProvider} from '#/lib/ThemeContext'
import {EmptyState} from '#/view/com/util/EmptyState'
import {ErrorMessage} from '#/view/com/util/error/ErrorMessage'
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
import {Button, ButtonType} from '#/view/com/util/forms/Button'
import {
DropdownButton,
DropdownItem,
} from '#/view/com/util/forms/DropdownButton'
import {RadioGroup} from '#/view/com/util/forms/RadioGroup'
import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
import * as LoadingPlaceholder from '#/view/com/util/LoadingPlaceholder'
import {Text} from '#/view/com/util/text/Text'
import * as Toast from '#/view/com/util/Toast'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {ViewSelector} from '#/view/com/util/ViewSelector'
import * as Layout from '#/components/Layout'
const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs'] const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs']
export const DebugScreen = ({}: NativeStackScreenProps< export const DebugScreen = ({}: NativeStackScreenProps<
@@ -33,10 +38,12 @@ export const DebugScreen = ({}: NativeStackScreenProps<
} }
return ( return (
<ThemeProvider theme={colorScheme}> <ThemeProvider theme={colorScheme}>
<DebugInner <Layout.Screen>
colorScheme={colorScheme} <DebugInner
onToggleColorScheme={onToggleColorScheme} colorScheme={colorScheme}
/> onToggleColorScheme={onToggleColorScheme}
/>
</Layout.Screen>
</ThemeProvider> </ThemeProvider>
) )
} }
+293 -276
View File
@@ -21,6 +21,7 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {moderationOptsOverrideContext} from '#/state/preferences/moderation-opts' import {moderationOptsOverrideContext} from '#/state/preferences/moderation-opts'
import {FeedNotification} from '#/state/queries/notifications/types' import {FeedNotification} from '#/state/queries/notifications/types'
import { import {
@@ -28,7 +29,6 @@ import {
shouldFilterNotif, shouldFilterNotif,
} from '#/state/queries/notifications/util' } from '#/state/queries/notifications/util'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {CenteredView, ScrollView} from '#/view/com/util/Views' import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {ProfileHeaderStandard} from '#/screens/Profile/Header/ProfileHeaderStandard' import {ProfileHeaderStandard} from '#/screens/Profile/Header/ProfileHeaderStandard'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
@@ -41,6 +41,7 @@ import {
ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottom, ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottom,
ChevronTop_Stroke2_Corner0_Rounded as ChevronTop, ChevronTop_Stroke2_Corner0_Rounded as ChevronTop,
} from '#/components/icons/Chevron' } from '#/components/icons/Chevron'
import * as Layout from '#/components/Layout'
import {H1, H3, P, Text} from '#/components/Typography' import {H1, H3, P, Text} from '#/components/Typography'
import {ScreenHider} from '../../components/moderation/ScreenHider' import {ScreenHider} from '../../components/moderation/ScreenHider'
import {FeedItem as NotifFeedItem} from '../com/notifications/FeedItem' import {FeedItem as NotifFeedItem} from '../com/notifications/FeedItem'
@@ -264,309 +265,325 @@ export const DebugModScreen = ({}: NativeStackScreenProps<
}, [post, modOpts]) }, [post, modOpts])
return ( return (
<moderationOptsOverrideContext.Provider value={modOpts}> <Layout.Screen>
<ScrollView> <moderationOptsOverrideContext.Provider value={modOpts}>
<CenteredView style={[t.atoms.bg, a.px_lg, a.py_lg]}> <ScrollView>
<H1 style={[a.text_5xl, a.font_bold, a.pb_lg]}>Moderation states</H1> <CenteredView style={[t.atoms.bg, a.px_lg, a.py_lg]}>
<H1 style={[a.text_5xl, a.font_bold, a.pb_lg]}>
Moderation states
</H1>
<Heading title="" subtitle="Scenario" /> <Heading title="" subtitle="Scenario" />
<ToggleButton.Group <ToggleButton.Group
label="Scenario" label="Scenario"
values={scenario} values={scenario}
onChange={setScenario}> onChange={setScenario}>
<ToggleButton.Button name="label" label="Label"> <ToggleButton.Button name="label" label="Label">
<ToggleButton.ButtonText>Label</ToggleButton.ButtonText> <ToggleButton.ButtonText>Label</ToggleButton.ButtonText>
</ToggleButton.Button> </ToggleButton.Button>
<ToggleButton.Button name="block" label="Block"> <ToggleButton.Button name="block" label="Block">
<ToggleButton.ButtonText>Block</ToggleButton.ButtonText> <ToggleButton.ButtonText>Block</ToggleButton.ButtonText>
</ToggleButton.Button> </ToggleButton.Button>
<ToggleButton.Button name="mute" label="Mute"> <ToggleButton.Button name="mute" label="Mute">
<ToggleButton.ButtonText>Mute</ToggleButton.ButtonText> <ToggleButton.ButtonText>Mute</ToggleButton.ButtonText>
</ToggleButton.Button> </ToggleButton.Button>
</ToggleButton.Group> </ToggleButton.Group>
{scenario[0] === 'label' && ( {scenario[0] === 'label' && (
<> <>
<View <View
style={[ style={[
a.border, a.border,
a.rounded_sm, a.rounded_sm,
a.mt_lg, a.mt_lg,
a.mb_lg, a.mb_lg,
a.p_lg, a.p_lg,
t.atoms.border_contrast_medium, t.atoms.border_contrast_medium,
]}> ]}>
<Toggle.Group
label="Toggle"
type="radio"
values={label}
onChange={setLabel}>
<View style={[a.flex_row, a.gap_md, a.flex_wrap]}>
{LABEL_VALUES.map(labelValue => {
let targetFixed = target[0]
if (
targetFixed !== 'account' &&
targetFixed !== 'profile'
) {
targetFixed = 'content'
}
const disabled =
isSelfLabel &&
LABELS[labelValue].flags.includes('no-self')
return (
<Toggle.Item
key={labelValue}
name={labelValue}
label={labelStrings[labelValue].name}
disabled={disabled}
style={disabled ? {opacity: 0.5} : undefined}>
<Toggle.Radio />
<Toggle.LabelText>{labelValue}</Toggle.LabelText>
</Toggle.Item>
)
})}
<Toggle.Item
name="custom"
label="Custom label"
disabled={isSelfLabel}
style={isSelfLabel ? {opacity: 0.5} : undefined}>
<Toggle.Radio />
<Toggle.LabelText>Custom label</Toggle.LabelText>
</Toggle.Item>
</View>
</Toggle.Group>
{label[0] === 'custom' ? (
<CustomLabelForm
def={customLabelDef}
setDef={setCustomLabelDef}
/>
) : (
<>
<View style={{height: 10}} />
<Divider />
</>
)}
<View style={{height: 10}} />
<SmallToggler label="Advanced">
<Toggle.Group <Toggle.Group
label="Toggle" label="Toggle"
type="checkbox" type="radio"
values={scenarioSwitches} values={label}
onChange={setScenarioSwitches}> onChange={setLabel}>
<View style={[a.gap_md, a.flex_row, a.flex_wrap, a.pt_md]}> <View style={[a.flex_row, a.gap_md, a.flex_wrap]}>
<Toggle.Item name="targetMe" label="Target is me"> {LABEL_VALUES.map(labelValue => {
<Toggle.Checkbox /> let targetFixed = target[0]
<Toggle.LabelText>Target is me</Toggle.LabelText> if (
</Toggle.Item> targetFixed !== 'account' &&
<Toggle.Item name="following" label="Following target"> targetFixed !== 'profile'
<Toggle.Checkbox /> ) {
<Toggle.LabelText>Following target</Toggle.LabelText> targetFixed = 'content'
</Toggle.Item> }
<Toggle.Item name="selfLabel" label="Self label"> const disabled =
<Toggle.Checkbox /> isSelfLabel &&
<Toggle.LabelText>Self label</Toggle.LabelText> LABELS[labelValue].flags.includes('no-self')
</Toggle.Item> return (
<Toggle.Item name="noAdult" label="Adult disabled"> <Toggle.Item
<Toggle.Checkbox /> key={labelValue}
<Toggle.LabelText>Adult disabled</Toggle.LabelText> name={labelValue}
</Toggle.Item> label={labelStrings[labelValue].name}
<Toggle.Item name="loggedOut" label="Logged out"> disabled={disabled}
<Toggle.Checkbox /> style={disabled ? {opacity: 0.5} : undefined}>
<Toggle.LabelText>Logged out</Toggle.LabelText> <Toggle.Radio />
<Toggle.LabelText>{labelValue}</Toggle.LabelText>
</Toggle.Item>
)
})}
<Toggle.Item
name="custom"
label="Custom label"
disabled={isSelfLabel}
style={isSelfLabel ? {opacity: 0.5} : undefined}>
<Toggle.Radio />
<Toggle.LabelText>Custom label</Toggle.LabelText>
</Toggle.Item> </Toggle.Item>
</View> </View>
</Toggle.Group> </Toggle.Group>
{LABELS[label[0] as keyof typeof LABELS]?.configurable !== {label[0] === 'custom' ? (
false && ( <CustomLabelForm
<View style={[a.mt_md]}> def={customLabelDef}
<Text setDef={setCustomLabelDef}
style={[a.font_bold, a.text_xs, t.atoms.text, a.pb_sm]}> />
Preference ) : (
</Text> <>
<Toggle.Group <View style={{height: 10}} />
label="Preference" <Divider />
type="radio" </>
values={visibility} )}
onChange={setVisiblity}>
<View <View style={{height: 10}} />
<SmallToggler label="Advanced">
<Toggle.Group
label="Toggle"
type="checkbox"
values={scenarioSwitches}
onChange={setScenarioSwitches}>
<View
style={[a.gap_md, a.flex_row, a.flex_wrap, a.pt_md]}>
<Toggle.Item name="targetMe" label="Target is me">
<Toggle.Checkbox />
<Toggle.LabelText>Target is me</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="following" label="Following target">
<Toggle.Checkbox />
<Toggle.LabelText>Following target</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="selfLabel" label="Self label">
<Toggle.Checkbox />
<Toggle.LabelText>Self label</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="noAdult" label="Adult disabled">
<Toggle.Checkbox />
<Toggle.LabelText>Adult disabled</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="loggedOut" label="Logged out">
<Toggle.Checkbox />
<Toggle.LabelText>Logged out</Toggle.LabelText>
</Toggle.Item>
</View>
</Toggle.Group>
{LABELS[label[0] as keyof typeof LABELS]?.configurable !==
false && (
<View style={[a.mt_md]}>
<Text
style={[ style={[
a.flex_row, a.font_bold,
a.gap_md, a.text_xs,
a.flex_wrap, t.atoms.text,
a.align_center, a.pb_sm,
]}> ]}>
<Toggle.Item name="hide" label="Hide"> Preference
</Text>
<Toggle.Group
label="Preference"
type="radio"
values={visibility}
onChange={setVisiblity}>
<View
style={[
a.flex_row,
a.gap_md,
a.flex_wrap,
a.align_center,
]}>
<Toggle.Item name="hide" label="Hide">
<Toggle.Radio />
<Toggle.LabelText>Hide</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="warn" label="Warn">
<Toggle.Radio />
<Toggle.LabelText>Warn</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="ignore" label="Ignore">
<Toggle.Radio />
<Toggle.LabelText>Ignore</Toggle.LabelText>
</Toggle.Item>
</View>
</Toggle.Group>
</View>
)}
</SmallToggler>
</View>
<View style={[a.flex_row, a.flex_wrap, a.gap_md]}>
<View>
<Text
style={[
a.font_bold,
a.text_xs,
t.atoms.text,
a.pl_md,
a.pb_xs,
]}>
Target
</Text>
<View
style={[
a.border,
a.rounded_full,
a.px_md,
a.py_sm,
t.atoms.border_contrast_medium,
t.atoms.bg,
]}>
<Toggle.Group
label="Target"
type="radio"
values={target}
onChange={setTarget}>
<View style={[a.flex_row, a.gap_md, a.flex_wrap]}>
<Toggle.Item name="account" label="Account">
<Toggle.Radio /> <Toggle.Radio />
<Toggle.LabelText>Hide</Toggle.LabelText> <Toggle.LabelText>Account</Toggle.LabelText>
</Toggle.Item> </Toggle.Item>
<Toggle.Item name="warn" label="Warn"> <Toggle.Item name="profile" label="Profile">
<Toggle.Radio /> <Toggle.Radio />
<Toggle.LabelText>Warn</Toggle.LabelText> <Toggle.LabelText>Profile</Toggle.LabelText>
</Toggle.Item> </Toggle.Item>
<Toggle.Item name="ignore" label="Ignore"> <Toggle.Item name="post" label="Post">
<Toggle.Radio /> <Toggle.Radio />
<Toggle.LabelText>Ignore</Toggle.LabelText> <Toggle.LabelText>Post</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="embed" label="Embed">
<Toggle.Radio />
<Toggle.LabelText>Embed</Toggle.LabelText>
</Toggle.Item> </Toggle.Item>
</View> </View>
</Toggle.Group> </Toggle.Group>
</View> </View>
)}
</SmallToggler>
</View>
<View style={[a.flex_row, a.flex_wrap, a.gap_md]}>
<View>
<Text
style={[
a.font_bold,
a.text_xs,
t.atoms.text,
a.pl_md,
a.pb_xs,
]}>
Target
</Text>
<View
style={[
a.border,
a.rounded_full,
a.px_md,
a.py_sm,
t.atoms.border_contrast_medium,
t.atoms.bg,
]}>
<Toggle.Group
label="Target"
type="radio"
values={target}
onChange={setTarget}>
<View style={[a.flex_row, a.gap_md, a.flex_wrap]}>
<Toggle.Item name="account" label="Account">
<Toggle.Radio />
<Toggle.LabelText>Account</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="profile" label="Profile">
<Toggle.Radio />
<Toggle.LabelText>Profile</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="post" label="Post">
<Toggle.Radio />
<Toggle.LabelText>Post</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="embed" label="Embed">
<Toggle.Radio />
<Toggle.LabelText>Embed</Toggle.LabelText>
</Toggle.Item>
</View>
</Toggle.Group>
</View> </View>
</View> </View>
</View>
</>
)}
<Spacer />
<Heading title="" subtitle="Results" />
<ToggleButton.Group label="Results" values={view} onChange={setView}>
<ToggleButton.Button name="post" label="Post">
<ToggleButton.ButtonText>Post</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="notifications" label="Notifications">
<ToggleButton.ButtonText>Notifications</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="account" label="Account">
<ToggleButton.ButtonText>Account</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="data" label="Data">
<ToggleButton.ButtonText>Data</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
<View
style={[
a.border,
a.rounded_sm,
a.mt_lg,
a.p_md,
t.atoms.border_contrast_medium,
]}>
{view[0] === 'post' && (
<>
<Heading title="Post" subtitle="in feed" />
<MockPostFeedItem post={post} moderation={postModeration} />
<Heading title="Post" subtitle="viewed directly" />
<MockPostThreadItem post={post} moderation={postModeration} />
<Heading title="Post" subtitle="reply in thread" />
<MockPostThreadItem
post={post}
moderation={postModeration}
reply
/>
</> </>
)} )}
{view[0] === 'notifications' && ( <Spacer />
<>
<Heading title="Notification" subtitle="quote or reply" />
<MockNotifItem notif={replyNotif} moderationOpts={modOpts} />
<View style={{height: 20}} />
<Heading title="Notification" subtitle="follow or like" />
<MockNotifItem notif={followNotif} moderationOpts={modOpts} />
</>
)}
{view[0] === 'account' && ( <Heading title="" subtitle="Results" />
<>
<Heading title="Account" subtitle="in listing" />
<MockAccountCard
profile={profile}
moderation={profileModeration}
/>
<Heading title="Account" subtitle="viewing directly" /> <ToggleButton.Group
<MockAccountScreen label="Results"
profile={profile} values={view}
moderation={profileModeration} onChange={setView}>
moderationOpts={modOpts} <ToggleButton.Button name="post" label="Post">
/> <ToggleButton.ButtonText>Post</ToggleButton.ButtonText>
</> </ToggleButton.Button>
)} <ToggleButton.Button name="notifications" label="Notifications">
<ToggleButton.ButtonText>Notifications</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="account" label="Account">
<ToggleButton.ButtonText>Account</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="data" label="Data">
<ToggleButton.ButtonText>Data</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
{view[0] === 'data' && ( <View
<> style={[
<ModerationUIView a.border,
label="Profile Moderation UI" a.rounded_sm,
mod={profileModeration} a.mt_lg,
/> a.p_md,
<ModerationUIView t.atoms.border_contrast_medium,
label="Post Moderation UI" ]}>
mod={postModeration} {view[0] === 'post' && (
/> <>
<DataView <Heading title="Post" subtitle="in feed" />
label={label[0]} <MockPostFeedItem post={post} moderation={postModeration} />
data={LABELS[label[0] as keyof typeof LABELS]}
/>
<DataView
label="Profile Moderation Data"
data={profileModeration}
/>
<DataView label="Post Moderation Data" data={postModeration} />
</>
)}
</View>
<View style={{height: 400}} /> <Heading title="Post" subtitle="viewed directly" />
</CenteredView> <MockPostThreadItem post={post} moderation={postModeration} />
</ScrollView>
</moderationOptsOverrideContext.Provider> <Heading title="Post" subtitle="reply in thread" />
<MockPostThreadItem
post={post}
moderation={postModeration}
reply
/>
</>
)}
{view[0] === 'notifications' && (
<>
<Heading title="Notification" subtitle="quote or reply" />
<MockNotifItem notif={replyNotif} moderationOpts={modOpts} />
<View style={{height: 20}} />
<Heading title="Notification" subtitle="follow or like" />
<MockNotifItem notif={followNotif} moderationOpts={modOpts} />
</>
)}
{view[0] === 'account' && (
<>
<Heading title="Account" subtitle="in listing" />
<MockAccountCard
profile={profile}
moderation={profileModeration}
/>
<Heading title="Account" subtitle="viewing directly" />
<MockAccountScreen
profile={profile}
moderation={profileModeration}
moderationOpts={modOpts}
/>
</>
)}
{view[0] === 'data' && (
<>
<ModerationUIView
label="Profile Moderation UI"
mod={profileModeration}
/>
<ModerationUIView
label="Post Moderation UI"
mod={postModeration}
/>
<DataView
label={label[0]}
data={LABELS[label[0] as keyof typeof LABELS]}
/>
<DataView
label="Profile Moderation Data"
data={profileModeration}
/>
<DataView
label="Post Moderation Data"
data={postModeration}
/>
</>
)}
</View>
<View style={{height: 400}} />
</CenteredView>
</ScrollView>
</moderationOptsOverrideContext.Provider>
</Layout.Screen>
) )
} }
+3 -5
View File
@@ -40,6 +40,7 @@ import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass' import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle' import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
import * as Layout from '#/components/Layout'
import * as ListCard from '#/components/ListCard' import * as ListCard from '#/components/ListCard'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Feeds'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Feeds'>
@@ -545,7 +546,7 @@ export function FeedsScreen(_props: Props) {
) )
return ( return (
<View style={[pal.view, styles.container]}> <Layout.Screen testID="FeedsScreen">
{isMobile && ( {isMobile && (
<ViewHeader <ViewHeader
title={_(msg`Feeds`)} title={_(msg`Feeds`)}
@@ -582,7 +583,7 @@ export function FeedsScreen(_props: Props) {
accessibilityHint="" accessibilityHint=""
/> />
)} )}
</View> </Layout.Screen>
) )
} }
@@ -768,9 +769,6 @@ function FeedsAboutHeader() {
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: {
flex: 1,
},
list: { list: {
height: '100%', height: '100%',
}, },
+12 -9
View File
@@ -1,5 +1,5 @@
import React from 'react' import React from 'react'
import {ActivityIndicator, StyleSheet, View} from 'react-native' import {ActivityIndicator, StyleSheet} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {PROD_DEFAULT_FEED} from '#/lib/constants' import {PROD_DEFAULT_FEED} from '#/lib/constants'
@@ -23,12 +23,13 @@ import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useLoggedOutViewControls} from '#/state/shell/logged-out'
import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed' import {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
import {FeedPage} from '#/view/com/feeds/FeedPage' import {FeedPage} from '#/view/com/feeds/FeedPage'
import {HomeHeader} from '#/view/com/home/HomeHeader'
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager' import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState' import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState'
import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState' import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState'
import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed' import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed'
import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned' import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
import {HomeHeader} from '../com/home/HomeHeader' import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'> type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'>
export function HomeScreen(props: Props) { export function HomeScreen(props: Props) {
@@ -70,17 +71,19 @@ export function HomeScreen(props: Props) {
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) { if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
return ( return (
<HomeScreenReady <Layout.Screen testID="HomeScreen">
{...props} <HomeScreenReady
preferences={preferences} {...props}
pinnedFeedInfos={pinnedFeedInfos} preferences={preferences}
/> pinnedFeedInfos={pinnedFeedInfos}
/>
</Layout.Screen>
) )
} else { } else {
return ( return (
<View style={styles.loading}> <Layout.Screen style={styles.loading}>
<ActivityIndicator size="large" /> <ActivityIndicator size="large" />
</View> </Layout.Screen>
) )
} }
} }
+227 -224
View File
@@ -19,9 +19,10 @@ import {useModalControls} from '#/state/modals'
import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences' import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {Button} from '#/view/com/util/forms/Button' import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {Text} from '../com/util/text/Text' import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
@@ -76,232 +77,234 @@ export function LanguageSettingsScreen(_props: Props) {
}, [langPrefs.contentLanguages]) }, [langPrefs.contentLanguages])
return ( return (
<CenteredView <Layout.Screen testID="PreferencesLanguagesScreen">
style={[ <CenteredView
pal.view, style={[
pal.border, pal.view,
styles.container, pal.border,
isTabletOrDesktop && styles.desktopContainer, styles.container,
]}> isTabletOrDesktop && styles.desktopContainer,
<ViewHeader title={_(msg`Language Settings`)} showOnDesktop /> ]}>
<ViewHeader title={_(msg`Language Settings`)} showOnDesktop />
<View style={{paddingTop: 20, paddingHorizontal: 20}}> <View style={{paddingTop: 20, paddingHorizontal: 20}}>
{/* APP LANGUAGE */} {/* APP LANGUAGE */}
<View style={{paddingBottom: 20}}> <View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}> <Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>App Language</Trans> <Trans>App Language</Trans>
</Text>
<Text style={[pal.text, s.pb10]}>
<Trans>
Select your app language for the default text to display in the
app.
</Trans>
</Text>
<View style={{position: 'relative'}}>
<RNPickerSelect
placeholder={{}}
value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
onValueChange={onChangeAppLanguage}
items={APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
label: l.name,
value: l.code2,
key: l.code2,
}))}
style={{
inputAndroid: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputIOS: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputWeb: {
cursor: 'pointer',
// @ts-ignore web only
'-moz-appearance': 'none',
'-webkit-appearance': 'none',
appearance: 'none',
outline: 0,
borderWidth: 0,
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
fontFamily: 'inherit',
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
}}
/>
<View
style={{
position: 'absolute',
top: 1,
right: 1,
bottom: 1,
width: 40,
backgroundColor: pal.viewLight.backgroundColor,
borderRadius: 24,
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
}}>
<FontAwesomeIcon
icon="chevron-down"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
</View>
</View>
<View
style={{
height: 1,
backgroundColor: pal.border.borderColor,
marginBottom: 20,
}}
/>
{/* PRIMARY LANGUAGE */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>Primary Language</Trans>
</Text>
<Text style={[pal.text, s.pb10]}>
<Trans>
Select your preferred language for translations in your feed.
</Trans>
</Text>
<View style={{position: 'relative'}}>
<RNPickerSelect
placeholder={{}}
value={langPrefs.primaryLanguage}
onValueChange={onChangePrimaryLanguage}
items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
label: l.name,
value: l.code2,
key: l.code2 + l.code3,
}))}
style={{
inputAndroid: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputIOS: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputWeb: {
cursor: 'pointer',
// @ts-ignore web only
'-moz-appearance': 'none',
'-webkit-appearance': 'none',
appearance: 'none',
outline: 0,
borderWidth: 0,
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
fontFamily: 'inherit',
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
}}
/>
<View
style={{
position: 'absolute',
top: 1,
right: 1,
bottom: 1,
width: 40,
backgroundColor: pal.viewLight.backgroundColor,
borderRadius: 24,
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
}}>
<FontAwesomeIcon
icon="chevron-down"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
</View>
</View>
<View
style={{
height: 1,
backgroundColor: pal.border.borderColor,
marginBottom: 20,
}}
/>
{/* CONTENT LANGUAGES */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>Content Languages</Trans>
</Text>
<Text style={[pal.text, s.pb10]}>
<Trans>
Select which languages you want your subscribed feeds to include.
If none are selected, all languages will be shown.
</Trans>
</Text>
<Button
type="default"
onPress={onPressContentLanguages}
style={styles.button}>
<FontAwesomeIcon
icon={myLanguages.length ? 'check' : 'plus'}
style={pal.text as FontAwesomeIconStyle}
/>
<Text
type="button"
style={[pal.text, {flexShrink: 1, overflow: 'hidden'}]}
numberOfLines={1}>
{myLanguages.length ? myLanguages : _(msg`Select languages`)}
</Text> </Text>
</Button> <Text style={[pal.text, s.pb10]}>
<Trans>
Select your app language for the default text to display in the
app.
</Trans>
</Text>
<View style={{position: 'relative'}}>
<RNPickerSelect
placeholder={{}}
value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
onValueChange={onChangeAppLanguage}
items={APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
label: l.name,
value: l.code2,
key: l.code2,
}))}
style={{
inputAndroid: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputIOS: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputWeb: {
cursor: 'pointer',
// @ts-ignore web only
'-moz-appearance': 'none',
'-webkit-appearance': 'none',
appearance: 'none',
outline: 0,
borderWidth: 0,
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
fontFamily: 'inherit',
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
}}
/>
<View
style={{
position: 'absolute',
top: 1,
right: 1,
bottom: 1,
width: 40,
backgroundColor: pal.viewLight.backgroundColor,
borderRadius: 24,
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
}}>
<FontAwesomeIcon
icon="chevron-down"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
</View>
</View>
<View
style={{
height: 1,
backgroundColor: pal.border.borderColor,
marginBottom: 20,
}}
/>
{/* PRIMARY LANGUAGE */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>Primary Language</Trans>
</Text>
<Text style={[pal.text, s.pb10]}>
<Trans>
Select your preferred language for translations in your feed.
</Trans>
</Text>
<View style={{position: 'relative'}}>
<RNPickerSelect
placeholder={{}}
value={langPrefs.primaryLanguage}
onValueChange={onChangePrimaryLanguage}
items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
label: l.name,
value: l.code2,
key: l.code2 + l.code3,
}))}
style={{
inputAndroid: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputIOS: {
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
inputWeb: {
cursor: 'pointer',
// @ts-ignore web only
'-moz-appearance': 'none',
'-webkit-appearance': 'none',
appearance: 'none',
outline: 0,
borderWidth: 0,
backgroundColor: pal.viewLight.backgroundColor,
color: pal.text.color,
fontSize: 14,
fontFamily: 'inherit',
letterSpacing: 0.5,
fontWeight: '600',
paddingHorizontal: 14,
paddingVertical: 8,
borderRadius: 24,
},
}}
/>
<View
style={{
position: 'absolute',
top: 1,
right: 1,
bottom: 1,
width: 40,
backgroundColor: pal.viewLight.backgroundColor,
borderRadius: 24,
pointerEvents: 'none',
alignItems: 'center',
justifyContent: 'center',
}}>
<FontAwesomeIcon
icon="chevron-down"
style={pal.text as FontAwesomeIconStyle}
/>
</View>
</View>
</View>
<View
style={{
height: 1,
backgroundColor: pal.border.borderColor,
marginBottom: 20,
}}
/>
{/* CONTENT LANGUAGES */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>Content Languages</Trans>
</Text>
<Text style={[pal.text, s.pb10]}>
<Trans>
Select which languages you want your subscribed feeds to
include. If none are selected, all languages will be shown.
</Trans>
</Text>
<Button
type="default"
onPress={onPressContentLanguages}
style={styles.button}>
<FontAwesomeIcon
icon={myLanguages.length ? 'check' : 'plus'}
style={pal.text as FontAwesomeIconStyle}
/>
<Text
type="button"
style={[pal.text, {flexShrink: 1, overflow: 'hidden'}]}
numberOfLines={1}>
{myLanguages.length ? myLanguages : _(msg`Select languages`)}
</Text>
</Button>
</View>
</View> </View>
</View> </CenteredView>
</CenteredView> </Layout.Screen>
) )
} }
+3 -2
View File
@@ -16,6 +16,7 @@ import {MyLists} from '#/view/com/lists/MyLists'
import {Button} from '#/view/com/util/forms/Button' import {Button} from '#/view/com/util/forms/Button'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
export function ListsScreen({}: Props) { export function ListsScreen({}: Props) {
@@ -48,7 +49,7 @@ export function ListsScreen({}: Props) {
}, [openModal, navigation]) }, [openModal, navigation])
return ( return (
<View style={s.hContentRegion} testID="listsScreen"> <Layout.Screen testID="listsScreen">
<SimpleViewHeader <SimpleViewHeader
showBackButton={isMobile} showBackButton={isMobile}
style={[ style={[
@@ -86,6 +87,6 @@ export function ListsScreen({}: Props) {
</View> </View>
</SimpleViewHeader> </SimpleViewHeader>
<MyLists filter="curate" style={s.flexGrow1} /> <MyLists filter="curate" style={s.flexGrow1} />
</View> </Layout.Screen>
) )
} }
+9 -8
View File
@@ -5,16 +5,17 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo' import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {getEntries} from '#/logger/logDump' import {getEntries} from '#/logger/logDump'
import {useTickEveryMinute} from '#/state/shell' import {useTickEveryMinute} from '#/state/shell'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {usePalette} from 'lib/hooks/usePalette' import {Text} from '#/view/com/util/text/Text'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {s} from 'lib/styles' import {ScrollView} from '#/view/com/util/Views'
import {Text} from '../com/util/text/Text' import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from '../com/util/Views'
export function LogScreen({}: NativeStackScreenProps< export function LogScreen({}: NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -42,7 +43,7 @@ export function LogScreen({}: NativeStackScreenProps<
} }
return ( return (
<View style={[s.flex1]}> <Layout.Screen>
<ViewHeader title="Log" /> <ViewHeader title="Log" />
<ScrollView style={s.flex1}> <ScrollView style={s.flex1}>
{getEntries() {getEntries()
@@ -91,7 +92,7 @@ export function LogScreen({}: NativeStackScreenProps<
})} })}
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+74 -71
View File
@@ -20,10 +20,11 @@ import {logger} from '#/logger'
import {useMyBlockedAccountsQuery} from '#/state/queries/my-blocked-accounts' import {useMyBlockedAccountsQuery} from '#/state/queries/my-blocked-accounts'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {ProfileCard} from '#/view/com/profile/ProfileCard' import {ProfileCard} from '#/view/com/profile/ProfileCard'
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {ErrorScreen} from '../com/util/error/ErrorScreen' import * as Layout from '#/components/Layout'
import {Text} from '../com/util/text/Text'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -95,76 +96,78 @@ export function ModerationBlockedAccounts({}: Props) {
/> />
) )
return ( return (
<CenteredView <Layout.Screen testID="blockedAccountsScreen">
style={[ <CenteredView
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="blockedAccountsScreen">
<ViewHeader title={_(msg`Blocked Accounts`)} showOnDesktop />
<Text
type="sm"
style={[ style={[
styles.description, styles.container,
pal.text, isTabletOrDesktop && styles.containerDesktop,
isTabletOrDesktop && styles.descriptionDesktop, pal.view,
]}> pal.border,
<Trans> ]}
Blocked accounts cannot reply in your threads, mention you, or testID="blockedAccountsScreen">
otherwise interact with you. You will not see their content and they <ViewHeader title={_(msg`Blocked Accounts`)} showOnDesktop />
will be prevented from seeing yours. <Text
</Trans> type="sm"
</Text> style={[
{isEmpty ? ( styles.description,
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}> pal.text,
{isError ? ( isTabletOrDesktop && styles.descriptionDesktop,
<ErrorScreen ]}>
title="Oops!" <Trans>
message={cleanError(error)} Blocked accounts cannot reply in your threads, mention you, or
onPressTryAgain={refetch} otherwise interact with you. You will not see their content and they
/> will be prevented from seeing yours.
) : ( </Trans>
<View style={[styles.empty, pal.viewLight]}> </Text>
<Text type="lg" style={[pal.text, styles.emptyText]}> {isEmpty ? (
<Trans> <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
You have not blocked any accounts yet. To block an account, go {isError ? (
to their profile and select "Block account" from the menu on <ErrorScreen
their account. title="Oops!"
</Trans> message={cleanError(error)}
</Text> onPressTryAgain={refetch}
</View> />
)} ) : (
</View> <View style={[styles.empty, pal.viewLight]}>
) : ( <Text type="lg" style={[pal.text, styles.emptyText]}>
<FlatList <Trans>
style={[!isTabletOrDesktop && styles.flex1]} You have not blocked any accounts yet. To block an account,
data={profiles} go to their profile and select "Block account" from the menu
keyExtractor={(item: ActorDefs.ProfileView) => item.did} on their account.
refreshControl={ </Trans>
<RefreshControl </Text>
refreshing={isPTRing} </View>
onRefresh={onRefresh} )}
tintColor={pal.colors.text} </View>
titleColor={pal.colors.text} ) : (
/> <FlatList
} style={[!isTabletOrDesktop && styles.flex1]}
onEndReached={onEndReached} data={profiles}
renderItem={renderItem} keyExtractor={(item: ActorDefs.ProfileView) => item.did}
initialNumToRender={15} refreshControl={
// FIXME(dan) <RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />} {(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View> </View>
)} )}
// @ts-ignore our .web version only -prf // @ts-ignore our .web version only -prf
desktopFixedHeight desktopFixedHeight
/> />
)} )}
</CenteredView> </CenteredView>
</Layout.Screen>
) )
} }
+3 -2
View File
@@ -16,6 +16,7 @@ import {MyLists} from '#/view/com/lists/MyLists'
import {Button} from '#/view/com/util/forms/Button' import {Button} from '#/view/com/util/forms/Button'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader' import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ModerationModlists'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ModerationModlists'>
export function ModerationModlistsScreen({}: Props) { export function ModerationModlistsScreen({}: Props) {
@@ -48,7 +49,7 @@ export function ModerationModlistsScreen({}: Props) {
}, [openModal, navigation]) }, [openModal, navigation])
return ( return (
<View style={s.hContentRegion} testID="moderationModlistsScreen"> <Layout.Screen testID="moderationModlistsScreen">
<SimpleViewHeader <SimpleViewHeader
showBackButton={isMobile} showBackButton={isMobile}
style={ style={
@@ -82,6 +83,6 @@ export function ModerationModlistsScreen({}: Props) {
</View> </View>
</SimpleViewHeader> </SimpleViewHeader>
<MyLists filter="mod" style={s.flexGrow1} /> <MyLists filter="mod" style={s.flexGrow1} />
</View> </Layout.Screen>
) )
} }
+73 -70
View File
@@ -20,10 +20,11 @@ import {logger} from '#/logger'
import {useMyMutedAccountsQuery} from '#/state/queries/my-muted-accounts' import {useMyMutedAccountsQuery} from '#/state/queries/my-muted-accounts'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {ProfileCard} from '#/view/com/profile/ProfileCard' import {ProfileCard} from '#/view/com/profile/ProfileCard'
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {ErrorScreen} from '../com/util/error/ErrorScreen' import * as Layout from '#/components/Layout'
import {Text} from '../com/util/text/Text'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -95,75 +96,77 @@ export function ModerationMutedAccounts({}: Props) {
/> />
) )
return ( return (
<CenteredView <Layout.Screen testID="mutedAccountsScreen">
style={[ <CenteredView
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="mutedAccountsScreen">
<ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop />
<Text
type="sm"
style={[ style={[
styles.description, styles.container,
pal.text, isTabletOrDesktop && styles.containerDesktop,
isTabletOrDesktop && styles.descriptionDesktop, pal.view,
]}> pal.border,
<Trans> ]}
Muted accounts have their posts removed from your feed and from your testID="mutedAccountsScreen">
notifications. Mutes are completely private. <ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop />
</Trans> <Text
</Text> type="sm"
{isEmpty ? ( style={[
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}> styles.description,
{isError ? ( pal.text,
<ErrorScreen isTabletOrDesktop && styles.descriptionDesktop,
title="Oops!" ]}>
message={cleanError(error)} <Trans>
onPressTryAgain={refetch} Muted accounts have their posts removed from your feed and from your
/> notifications. Mutes are completely private.
) : ( </Trans>
<View style={[styles.empty, pal.viewLight]}> </Text>
<Text type="lg" style={[pal.text, styles.emptyText]}> {isEmpty ? (
<Trans> <View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
You have not muted any accounts yet. To mute an account, go to {isError ? (
their profile and select "Mute account" from the menu on their <ErrorScreen
account. title="Oops!"
</Trans> message={cleanError(error)}
</Text> onPressTryAgain={refetch}
</View> />
)} ) : (
</View> <View style={[styles.empty, pal.viewLight]}>
) : ( <Text type="lg" style={[pal.text, styles.emptyText]}>
<FlatList <Trans>
style={[!isTabletOrDesktop && styles.flex1]} You have not muted any accounts yet. To mute an account, go
data={profiles} to their profile and select "Mute account" from the menu on
keyExtractor={item => item.did} their account.
refreshControl={ </Trans>
<RefreshControl </Text>
refreshing={isPTRing} </View>
onRefresh={onRefresh} )}
tintColor={pal.colors.text} </View>
titleColor={pal.colors.text} ) : (
/> <FlatList
} style={[!isTabletOrDesktop && styles.flex1]}
onEndReached={onEndReached} data={profiles}
renderItem={renderItem} keyExtractor={item => item.did}
initialNumToRender={15} refreshControl={
// FIXME(dan) <RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
ListFooterComponent={() => ( ListFooterComponent={() => (
<View style={styles.footer}> <View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />} {(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View> </View>
)} )}
// @ts-ignore our .web version only -prf // @ts-ignore our .web version only -prf
desktopFixedHeight desktopFixedHeight
/> />
)} )}
</CenteredView> </CenteredView>
</Layout.Screen>
) )
} }
+13 -11
View File
@@ -1,19 +1,21 @@
import React from 'react' import React from 'react'
import {StyleSheet, View} from 'react-native' import {StyleSheet, View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import { import {
useNavigation,
StackActions, StackActions,
useFocusEffect, useFocusEffect,
useNavigation,
} from '@react-navigation/native' } from '@react-navigation/native'
import {ViewHeader} from '../com/util/ViewHeader'
import {Text} from '../com/util/text/Text' import {usePalette} from '#/lib/hooks/usePalette'
import {Button} from 'view/com/util/forms/Button' import {NavigationProp} from '#/lib/routes/types'
import {NavigationProp} from 'lib/routes/types' import {s} from '#/lib/styles'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro' import {Button} from '#/view/com/util/forms/Button'
import {useLingui} from '@lingui/react' import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
export const NotFoundScreen = () => { export const NotFoundScreen = () => {
const pal = usePalette('default') const pal = usePalette('default')
@@ -38,7 +40,7 @@ export const NotFoundScreen = () => {
}, [navigation, canGoBack]) }, [navigation, canGoBack])
return ( return (
<View testID="notFoundView" style={pal.view}> <Layout.Screen testID="notFoundView">
<ViewHeader title={_(msg`Page Not Found`)} /> <ViewHeader title={_(msg`Page Not Found`)} />
<View style={styles.container}> <View style={styles.container}>
<Text type="title-2xl" style={[pal.text, s.mb10]}> <Text type="title-2xl" style={[pal.text, s.mb10]}>
@@ -61,7 +63,7 @@ export const NotFoundScreen = () => {
onPress={onPressHome} onPress={onPressHome}
/> />
</View> </View>
</View> </Layout.Screen>
) )
} }
+32 -32
View File
@@ -34,6 +34,7 @@ import {CenteredView} from '#/view/com/util/Views'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button} from '#/components/Button' import {Button} from '#/components/Button'
import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2' import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2'
import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link' import {Link} from '#/components/Link'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -192,39 +193,38 @@ export function NotificationsScreen({route: {params}}: Props) {
}, [renderButton, isLoadingLatest]) }, [renderButton, isLoadingLatest])
return ( return (
<CenteredView <Layout.Screen testID="notificationsScreen">
testID="notificationsScreen" <CenteredView style={[a.flex_1, {paddingTop: 2}]} sideBorders={true}>
style={[s.hContentRegion, {paddingTop: 2}]} <ViewHeader
sideBorders={true}> title={_(msg`Notifications`)}
<ViewHeader canGoBack={false}
title={_(msg`Notifications`)} showBorder={true}
canGoBack={false} renderButton={renderHeaderSpinner}
showBorder={true}
renderButton={renderHeaderSpinner}
/>
<MainScrollProvider>
<Feed
onScrolledDownChange={setIsScrolledDown}
scrollElRef={scrollElRef}
ListHeaderComponent={ListHeaderComponent}
overridePriorityNotifications={params?.show === 'all'}
/> />
</MainScrollProvider> <MainScrollProvider>
{(isScrolledDown || hasNew) && ( <Feed
<LoadLatestBtn onScrolledDownChange={setIsScrolledDown}
onPress={onPressLoadLatest} scrollElRef={scrollElRef}
label={_(msg`Load new notifications`)} ListHeaderComponent={ListHeaderComponent}
showIndicator={hasNew} overridePriorityNotifications={params?.show === 'all'}
/>
</MainScrollProvider>
{(isScrolledDown || hasNew) && (
<LoadLatestBtn
onPress={onPressLoadLatest}
label={_(msg`Load new notifications`)}
showIndicator={hasNew}
/>
)}
<FAB
testID="composeFAB"
onPress={() => openComposer({})}
icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />}
accessibilityRole="button"
accessibilityLabel={_(msg`New post`)}
accessibilityHint=""
/> />
)} </CenteredView>
<FAB </Layout.Screen>
testID="composeFAB"
onPress={() => openComposer({})}
icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />}
accessibilityRole="button"
accessibilityLabel={_(msg`New post`)}
accessibilityHint=""
/>
</CenteredView>
) )
} }
+49 -46
View File
@@ -13,6 +13,7 @@ import {atoms as a, useTheme} from '#/alf'
import {Admonition} from '#/components/Admonition' import {Admonition} from '#/components/Admonition'
import {Error} from '#/components/Error' import {Error} from '#/components/Error'
import * as Toggle from '#/components/forms/Toggle' import * as Toggle from '#/components/forms/Toggle'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography' import {Text} from '#/components/Typography'
@@ -35,52 +36,54 @@ export function NotificationsSettingsScreen({}: Props) {
: serverPriority : serverPriority
return ( return (
<ScrollView stickyHeaderIndices={[0]}> <Layout.Screen>
<ViewHeader <ScrollView stickyHeaderIndices={[0]}>
title={_(msg`Notification Settings`)} <ViewHeader
showOnDesktop title={_(msg`Notification Settings`)}
showBorder showOnDesktop
/> showBorder
{isQueryError ? (
<Error
title={_(msg`Oops!`)}
message={_(msg`Something went wrong!`)}
onRetry={refetch}
sideBorders={false}
/> />
) : ( {isQueryError ? (
<View style={[a.p_lg, a.gap_md]}> <Error
<Text style={[a.text_lg, a.font_bold]}> title={_(msg`Oops!`)}
<FontAwesomeIcon icon="flask" style={t.atoms.text} />{' '} message={_(msg`Something went wrong!`)}
<Trans>Notification filters</Trans> onRetry={refetch}
</Text> sideBorders={false}
<Toggle.Group />
label={_(msg`Priority notifications`)} ) : (
type="checkbox" <View style={[a.p_lg, a.gap_md]}>
values={priority ? ['enabled'] : []} <Text style={[a.text_lg, a.font_bold]}>
onChange={onChangePriority} <FontAwesomeIcon icon="flask" style={t.atoms.text} />{' '}
disabled={typeof priority !== 'boolean' || isMutationPending}> <Trans>Notification filters</Trans>
<View> </Text>
<Toggle.Item <Toggle.Group
name="enabled" label={_(msg`Priority notifications`)}
label={_(msg`Enable priority notifications`)} type="checkbox"
style={[a.justify_between, a.py_sm]}> values={priority ? ['enabled'] : []}
<Toggle.LabelText> onChange={onChangePriority}
<Trans>Enable priority notifications</Trans> disabled={typeof priority !== 'boolean' || isMutationPending}>
</Toggle.LabelText> <View>
{!data ? <Loader size="md" /> : <Toggle.Platform />} <Toggle.Item
</Toggle.Item> name="enabled"
</View> label={_(msg`Enable priority notifications`)}
</Toggle.Group> style={[a.justify_between, a.py_sm]}>
<Admonition type="warning" style={[a.mt_sm]}> <Toggle.LabelText>
<Trans> <Trans>Enable priority notifications</Trans>
Experimental: When this preference is enabled, you'll only receive </Toggle.LabelText>
reply and quote notifications from users you follow. We'll {!data ? <Loader size="md" /> : <Toggle.Platform />}
continue to add more controls here over time. </Toggle.Item>
</Trans> </View>
</Admonition> </Toggle.Group>
</View> <Admonition type="warning" style={[a.mt_sm]}>
)} <Trans>
</ScrollView> Experimental: When this preference is enabled, you'll only
receive reply and quote notifications from users you follow.
We'll continue to add more controls here over time.
</Trans>
</Admonition>
</View>
)}
</ScrollView>
</Layout.Screen>
) )
} }
+8 -7
View File
@@ -2,11 +2,12 @@ import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' import {PostThread as PostThreadComponent} from '#/view/com/post-thread/PostThread'
import {makeRecordUri} from 'lib/strings/url-helpers' import {atoms as a} from '#/alf'
import {s} from 'lib/styles' import * as Layout from '#/components/Layout'
import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
export function PostThreadScreen({route}: Props) { export function PostThreadScreen({route}: Props) {
@@ -22,10 +23,10 @@ export function PostThreadScreen({route}: Props) {
) )
return ( return (
<View style={s.hContentRegion}> <Layout.Screen testID="postThreadScreen">
<View style={s.flex1}> <View style={a.flex_1}>
<PostThreadComponent uri={uri} /> <PostThreadComponent uri={uri} />
</View> </View>
</View> </Layout.Screen>
) )
} }
@@ -10,17 +10,17 @@ import {
EmbedPlayerSource, EmbedPlayerSource,
externalEmbedLabels, externalEmbedLabels,
} from '#/lib/strings/embed-player' } from '#/lib/strings/embed-player'
import {s} from '#/lib/styles'
import { import {
useExternalEmbedsPrefs, useExternalEmbedsPrefs,
useSetExternalEmbedPref, useSetExternalEmbedPref,
} from '#/state/preferences' } from '#/state/preferences'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {ToggleButton} from '#/view/com/util/forms/ToggleButton' import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import {SimpleViewHeader} from '../com/util/SimpleViewHeader' import * as Layout from '#/components/Layout'
import {Text} from '../com/util/text/Text'
import {ScrollView} from '../com/util/Views'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -38,7 +38,7 @@ export function PreferencesExternalEmbeds({}: Props) {
) )
return ( return (
<View style={s.hContentRegion} testID="preferencesExternalEmbedsScreen"> <Layout.Screen testID="preferencesExternalEmbedsScreen">
<ScrollView <ScrollView
// @ts-ignore web only -prf // @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}} dataSet={{'stable-gutters': 1}}
@@ -81,7 +81,7 @@ export function PreferencesExternalEmbeds({}: Props) {
/> />
))} ))}
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
@@ -17,6 +17,7 @@ import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps< type Props = NativeStackScreenProps<
CommonNavigatorParams, CommonNavigatorParams,
@@ -35,7 +36,7 @@ export function PreferencesFollowingFeed({}: Props) {
) )
return ( return (
<View testID="preferencesHomeFeedScreen" style={s.hContentRegion}> <Layout.Screen testID="preferencesHomeFeedScreen">
<ScrollView <ScrollView
// @ts-ignore web only -sfn // @ts-ignore web only -sfn
dataSet={{'stable-gutters': 1}} dataSet={{'stable-gutters': 1}}
@@ -185,7 +186,7 @@ export function PreferencesFollowingFeed({}: Props) {
</View> </View>
</View> </View>
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+3 -2
View File
@@ -18,6 +18,7 @@ import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text' import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views' import {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'>
export function PreferencesThreads({}: Props) { export function PreferencesThreads({}: Props) {
@@ -38,7 +39,7 @@ export function PreferencesThreads({}: Props) {
) )
return ( return (
<View testID="preferencesThreadsScreen" style={s.hContentRegion}> <Layout.Screen testID="preferencesThreadsScreen">
<ScrollView <ScrollView
// @ts-ignore web only -prf // @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}} dataSet={{'stable-gutters': 1}}
@@ -134,7 +135,7 @@ export function PreferencesThreads({}: Props) {
<ActivityIndicator style={a.flex_1} /> <ActivityIndicator style={a.flex_1} />
)} )}
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {msg, Trans} from '@lingui/macro'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from 'view/com/util/Link'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from 'view/com/util/Views'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {TextLink} from '#/view/com/util/Link'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'PrivacyPolicy'>
export const PrivacyPolicyScreen = (_props: Props) => { export const PrivacyPolicyScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const PrivacyPolicyScreen = (_props: Props) => {
) )
return ( return (
<View> <Layout.Screen>
<ViewHeader title={_(msg`Privacy Policy`)} /> <ViewHeader title={_(msg`Privacy Policy`)} />
<ScrollView style={[s.hContentRegion, pal.view]}> <ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}> <View style={[s.p20]}>
@@ -42,6 +44,6 @@ export const PrivacyPolicyScreen = (_props: Props) => {
</View> </View>
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+10 -1
View File
@@ -45,6 +45,7 @@ import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header'
import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed'
import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels'
import {web} from '#/alf' import {web} from '#/alf'
import * as Layout from '#/components/Layout'
import {ScreenHider} from '#/components/moderation/ScreenHider' import {ScreenHider} from '#/components/moderation/ScreenHider'
import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks' import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks'
import {navigate} from '#/Navigation' import {navigate} from '#/Navigation'
@@ -55,7 +56,15 @@ interface SectionRef {
} }
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Profile'>
export function ProfileScreen({route}: Props) { export function ProfileScreen(props: Props) {
return (
<Layout.Screen testID="profileScreen">
<ProfileScreenInner {...props} />
</Layout.Screen>
)
}
function ProfileScreenInner({route}: Props) {
const {_} = useLingui() const {_} = useLingui()
const {currentAccount} = useSession() const {currentAccount} = useSession()
const queryClient = useQueryClient() const queryClient = useQueryClient()
+30 -23
View File
@@ -61,6 +61,7 @@ import {
} from '#/components/icons/Heart2' } from '#/components/icons/Heart2'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import * as Layout from '#/components/Layout'
import {InlineLinkText} from '#/components/Link' import {InlineLinkText} from '#/components/Link'
import * as Menu from '#/components/Menu' import * as Menu from '#/components/Menu'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
@@ -96,36 +97,42 @@ export function ProfileFeedScreen(props: Props) {
if (error) { if (error) {
return ( return (
<CenteredView> <Layout.Screen testID="profileFeedScreenError">
<View style={[pal.view, pal.border, styles.notFoundContainer]}> <CenteredView>
<Text type="title-lg" style={[pal.text, s.mb10]}> <View style={[pal.view, pal.border, styles.notFoundContainer]}>
<Trans>Could not load feed</Trans> <Text type="title-lg" style={[pal.text, s.mb10]}>
</Text> <Trans>Could not load feed</Trans>
<Text type="md" style={[pal.text, s.mb20]}> </Text>
{error.toString()} <Text type="md" style={[pal.text, s.mb20]}>
</Text> {error.toString()}
</Text>
<View style={{flexDirection: 'row'}}> <View style={{flexDirection: 'row'}}>
<Button <Button
type="default" type="default"
accessibilityLabel={_(msg`Go back`)} accessibilityLabel={_(msg`Go back`)}
accessibilityHint={_(msg`Returns to previous page`)} accessibilityHint={_(msg`Returns to previous page`)}
onPress={onPressBack} onPress={onPressBack}
style={{flexShrink: 1}}> style={{flexShrink: 1}}>
<Text type="button" style={pal.text}> <Text type="button" style={pal.text}>
<Trans>Go Back</Trans> <Trans>Go Back</Trans>
</Text> </Text>
</Button> </Button>
</View>
</View> </View>
</View> </CenteredView>
</CenteredView> </Layout.Screen>
) )
} }
return resolvedUri ? ( return resolvedUri ? (
<ProfileFeedScreenIntermediate feedUri={resolvedUri.uri} /> <Layout.Screen>
<ProfileFeedScreenIntermediate feedUri={resolvedUri.uri} />
</Layout.Screen>
) : ( ) : (
<LoadingScreen /> <Layout.Screen>
<LoadingScreen />
</Layout.Screen>
) )
} }
+7 -7
View File
@@ -1,14 +1,14 @@
import React from 'react' import React from 'react'
import {View} from 'react-native'
import {msg} from '@lingui/macro' import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {makeRecordUri} from '#/lib/strings/url-helpers'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy'
import {makeRecordUri} from 'lib/strings/url-helpers' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {PostLikedBy as PostLikedByComponent} from '../com/post-thread/PostLikedBy' import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'>
export const ProfileFeedLikedByScreen = ({route}: Props) => { export const ProfileFeedLikedByScreen = ({route}: Props) => {
@@ -24,9 +24,9 @@ export const ProfileFeedLikedByScreen = ({route}: Props) => {
) )
return ( return (
<View style={{flex: 1}}> <Layout.Screen testID="postLikedByScreen">
<ViewHeader title={_(msg`Liked By`)} /> <ViewHeader title={_(msg`Liked By`)} />
<PostLikedByComponent uri={uri} /> <PostLikedByComponent uri={uri} />
</View> </Layout.Screen>
) )
} }
+13 -11
View File
@@ -3,14 +3,14 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' import {ProfileFollowers as ProfileFollowersComponent} from '#/view/com/profile/ProfileFollowers'
import {isWeb} from 'platform/detection' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists' import {ListHeaderDesktop} from '#/components/Lists'
import {ProfileFollowers as ProfileFollowersComponent} from '../com/profile/ProfileFollowers'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
export const ProfileFollowersScreen = ({route}: Props) => { export const ProfileFollowersScreen = ({route}: Props) => {
@@ -25,10 +25,12 @@ export const ProfileFollowersScreen = ({route}: Props) => {
) )
return ( return (
<CenteredView style={a.util_screen_outer} sideBorders={true}> <Layout.Screen testID="profileFollowersScreen">
<ListHeaderDesktop title={_(msg`Followers`)} /> <CenteredView sideBorders={true}>
<ViewHeader title={_(msg`Followers`)} showBorder={!isWeb} /> <ListHeaderDesktop title={_(msg`Followers`)} />
<ProfileFollowersComponent name={name} /> <ViewHeader title={_(msg`Followers`)} showBorder={!isWeb} />
</CenteredView> <ProfileFollowersComponent name={name} />
</CenteredView>
</Layout.Screen>
) )
} }
+13 -11
View File
@@ -3,14 +3,14 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native' import {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types' import {ProfileFollows as ProfileFollowsComponent} from '#/view/com/profile/ProfileFollows'
import {isWeb} from 'platform/detection' import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf' import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists' import {ListHeaderDesktop} from '#/components/Lists'
import {ProfileFollows as ProfileFollowsComponent} from '../com/profile/ProfileFollows'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
export const ProfileFollowsScreen = ({route}: Props) => { export const ProfileFollowsScreen = ({route}: Props) => {
@@ -25,10 +25,12 @@ export const ProfileFollowsScreen = ({route}: Props) => {
) )
return ( return (
<CenteredView style={a.util_screen_outer} sideBorders={true}> <Layout.Screen testID="profileFollowsScreen">
<ListHeaderDesktop title={_(msg`Following`)} /> <CenteredView sideBorders={true}>
<ViewHeader title={_(msg`Following`)} showBorder={!isWeb} /> <ListHeaderDesktop title={_(msg`Following`)} />
<ProfileFollowsComponent name={name} /> <ViewHeader title={_(msg`Following`)} showBorder={!isWeb} />
</CenteredView> <ProfileFollowsComponent name={name} />
</CenteredView>
</Layout.Screen>
) )
} }
+9
View File
@@ -73,6 +73,7 @@ import {CenteredView} from '#/view/com/util/Views'
import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen' import {ListHiddenScreen} from '#/screens/List/ListHiddenScreen'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import * as Hider from '#/components/moderation/Hider' import * as Hider from '#/components/moderation/Hider'
import * as Prompt from '#/components/Prompt' import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
@@ -87,6 +88,14 @@ interface SectionRef {
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'>
export function ProfileListScreen(props: Props) { export function ProfileListScreen(props: Props) {
return (
<Layout.Screen testID="profileListScreen">
<ProfileListScreenInner {...props} />
</Layout.Screen>
)
}
function ProfileListScreenInner(props: Props) {
const {_} = useLingui() const {_} = useLingui()
const {name: handleOrDid, rkey} = props.route.params const {name: handleOrDid, rkey} = props.route.params
const {data: resolvedUri, error: resolveError} = useResolveUriQuery( const {data: resolvedUri, error: resolveError} = useResolveUriQuery(
+106 -120
View File
@@ -32,6 +32,7 @@ import {NoSavedFeedsOfAnyType} from '#/screens/Feeds/NoSavedFeedsOfAnyType'
import {atoms as a, useTheme} from '#/alf' import {atoms as a, useTheme} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline' import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader' import {Loader} from '#/components/Loader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
@@ -106,120 +107,117 @@ function SavedFeedsInner({
}, [_, isDesktop, onSaveChanges, hasUnsavedChanges, isOverwritePending]) }, [_, isDesktop, onSaveChanges, hasUnsavedChanges, isOverwritePending])
return ( return (
<CenteredView <Layout.Screen>
style={[ <CenteredView
s.hContentRegion, style={[a.util_screen_outer]}
pal.border, sideBorders={isTabletOrDesktop}>
isTabletOrDesktop && styles.desktopContainer, <ViewHeader
]}> title={_(msg`Edit My Feeds`)}
<ViewHeader showOnDesktop
title={_(msg`Edit My Feeds`)} showBorder
showOnDesktop renderButton={renderHeaderBtn}
showBorder />
renderButton={renderHeaderBtn} <ScrollView style={[a.flex_1]} contentContainerStyle={[a.border_0]}>
/> {noSavedFeedsOfAnyType && (
<ScrollView style={s.flex1} contentContainerStyle={[styles.noBorder]}> <View style={[pal.border, a.border_b]}>
{noSavedFeedsOfAnyType && ( <NoSavedFeedsOfAnyType />
<View
style={[pal.border, {borderBottomWidth: StyleSheet.hairlineWidth}]}>
<NoSavedFeedsOfAnyType />
</View>
)}
<View style={[pal.text, pal.border, styles.title]}>
<Text type="title" style={pal.text}>
<Trans>Pinned Feeds</Trans>
</Text>
</View>
{preferences ? (
!pinnedFeeds.length ? (
<View
style={[
pal.border,
isMobile && s.flex1,
pal.viewLight,
styles.empty,
]}>
<Text type="lg" style={[pal.text]}>
<Trans>You don't have any pinned feeds.</Trans>
</Text>
</View> </View>
) : ( )}
pinnedFeeds.map(f => (
<ListItem
key={f.id}
feed={f}
isPinned
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : (
<ActivityIndicator style={{marginTop: 20}} />
)}
{noFollowingFeed && ( <View style={[pal.text, pal.border, styles.title]}>
<View <Text type="title" style={pal.text}>
style={[pal.border, {borderBottomWidth: StyleSheet.hairlineWidth}]}> <Trans>Pinned Feeds</Trans>
<NoFollowingFeed /> </Text>
</View> </View>
)}
<View style={[pal.text, pal.border, styles.title]}> {preferences ? (
<Text type="title" style={pal.text}> !pinnedFeeds.length ? (
<Trans>Saved Feeds</Trans> <View
</Text> style={[
</View> pal.border,
{preferences ? ( isMobile && s.flex1,
!unpinnedFeeds.length ? ( pal.viewLight,
<View styles.empty,
style={[ ]}>
pal.border, <Text type="lg" style={[pal.text]}>
isMobile && s.flex1, <Trans>You don't have any pinned feeds.</Trans>
pal.viewLight, </Text>
styles.empty, </View>
]}> ) : (
<Text type="lg" style={[pal.text]}> pinnedFeeds.map(f => (
<Trans>You don't have any saved feeds.</Trans> <ListItem
</Text> key={f.id}
</View> feed={f}
isPinned
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : ( ) : (
unpinnedFeeds.map(f => ( <ActivityIndicator style={{marginTop: 20}} />
<ListItem )}
key={f.id}
feed={f}
isPinned={false}
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : (
<ActivityIndicator style={{marginTop: 20}} />
)}
<View style={styles.footerText}> {noFollowingFeed && (
<Text type="sm" style={pal.textLight}> <View style={[pal.border, a.border_b]}>
<Trans> <NoFollowingFeed />
Feeds are custom algorithms that users build with a little coding </View>
expertise.{' '} )}
<TextLink
type="sm" <View style={[pal.text, pal.border, styles.title]}>
style={pal.link} <Text type="title" style={pal.text}>
href="https://github.com/bluesky-social/feed-generator" <Trans>Saved Feeds</Trans>
text={_(msg`See this guide`)} </Text>
/>{' '} </View>
for more information. {preferences ? (
</Trans> !unpinnedFeeds.length ? (
</Text> <View
</View> style={[
<View style={{height: 100}} /> pal.border,
</ScrollView> isMobile && s.flex1,
</CenteredView> pal.viewLight,
styles.empty,
]}>
<Text type="lg" style={[pal.text]}>
<Trans>You don't have any saved feeds.</Trans>
</Text>
</View>
) : (
unpinnedFeeds.map(f => (
<ListItem
key={f.id}
feed={f}
isPinned={false}
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : (
<ActivityIndicator style={{marginTop: 20}} />
)}
<View style={styles.footerText}>
<Text type="sm" style={pal.textLight}>
<Trans>
Feeds are custom algorithms that users build with a little
coding expertise.{' '}
<TextLink
type="sm"
style={pal.link}
href="https://github.com/bluesky-social/feed-generator"
text={_(msg`See this guide`)}
/>{' '}
for more information.
</Trans>
</Text>
</View>
<View style={{height: 100}} />
</ScrollView>
</CenteredView>
</Layout.Screen>
) )
} }
@@ -434,12 +432,6 @@ function FollowingFeedCard() {
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
desktopContainer: {
borderLeftWidth: 1,
borderRightWidth: 1,
// @ts-ignore only rendered on web
minHeight: '100vh',
},
empty: { empty: {
paddingHorizontal: 20, paddingHorizontal: 20,
paddingVertical: 20, paddingVertical: 20,
@@ -463,10 +455,4 @@ const styles = StyleSheet.create({
paddingTop: 22, paddingTop: 22,
paddingBottom: 100, paddingBottom: 100,
}, },
noBorder: {
borderBottomWidth: 0,
borderRightWidth: 0,
borderLeftWidth: 0,
borderTopWidth: 0,
},
}) })
+5 -3
View File
@@ -10,20 +10,20 @@ import {
import {msg, Trans} from '@lingui/macro' import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger' import {logger} from '#/logger'
import {isWeb} from '#/platform/detection' import {isWeb} from '#/platform/detection'
import {useModerationOpts} from '#/state/preferences/moderation-opts' import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useGetPopularFeedsQuery} from '#/state/queries/feed' import {useGetPopularFeedsQuery} from '#/state/queries/feed'
import {usePreferencesQuery} from '#/state/queries/preferences' import {usePreferencesQuery} from '#/state/queries/preferences'
import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows' import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows'
import {cleanError} from 'lib/strings/errors'
import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard' import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
import {List} from '#/view/com/util/List' import {List} from '#/view/com/util/List'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import { import {
FeedFeedLoadingPlaceholder, FeedFeedLoadingPlaceholder,
ProfileCardFeedLoadingPlaceholder, ProfileCardFeedLoadingPlaceholder,
} from 'view/com/util/LoadingPlaceholder' } from '#/view/com/util/LoadingPlaceholder'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {atoms as a, useTheme, ViewStyleProp} from '#/alf' import {atoms as a, useTheme, ViewStyleProp} from '#/alf'
import {Button} from '#/components/Button' import {Button} from '#/components/Button'
import * as FeedCard from '#/components/FeedCard' import * as FeedCard from '#/components/FeedCard'
@@ -564,6 +564,8 @@ export function Explore() {
[t, moderationOpts], [t, moderationOpts],
) )
// note: actually not a screen, instead it's nested within
// the search screen. so we don't need Layout.Screen
return ( return (
<List <List
data={items} data={items}
+3 -2
View File
@@ -65,6 +65,7 @@ import * as FeedCard from '#/components/FeedCard'
import {SearchInput} from '#/components/forms/SearchInput' import {SearchInput} from '#/components/forms/SearchInput'
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron' import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu' import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
import * as Layout from '#/components/Layout'
function Loader() { function Loader() {
const pal = usePalette('default') const pal = usePalette('default')
@@ -852,7 +853,7 @@ export function SearchScreen(
}, [setShowAutocomplete]) }, [setShowAutocomplete])
return ( return (
<View style={isWeb ? null : {flex: 1}}> <Layout.Screen testID="searchScreen">
<CenteredView <CenteredView
style={[ style={[
a.p_md, a.p_md,
@@ -957,7 +958,7 @@ export function SearchScreen(
headerHeight={headerHeight} headerHeight={headerHeight}
/> />
</View> </View>
</View> </Layout.Screen>
) )
} }
+3 -2
View File
@@ -57,6 +57,7 @@ import {atoms as a, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog' import {useDialogControl} from '#/components/Dialog'
import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog' import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
import * as Layout from '#/components/Layout'
import {Email2FAToggle} from './Email2FAToggle' import {Email2FAToggle} from './Email2FAToggle'
import {ExportCarDialog} from './ExportCarDialog' import {ExportCarDialog} from './ExportCarDialog'
@@ -286,7 +287,7 @@ export function SettingsScreen({}: Props) {
const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration() const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration()
return ( return (
<View style={s.hContentRegion} testID="settingsScreen"> <Layout.Screen testID="settingsScreen">
<ExportCarDialog control={exportCarControl} /> <ExportCarDialog control={exportCarControl} />
<BirthDateSettingsDialog control={birthdayControl} /> <BirthDateSettingsDialog control={birthdayControl} />
@@ -919,7 +920,7 @@ export function SettingsScreen({}: Props) {
</View> </View>
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+10 -5
View File
@@ -7,6 +7,7 @@ import {CenteredView} from '#/view/com/util/Views'
import {ListContained} from '#/view/screens/Storybook/ListContained' import {ListContained} from '#/view/screens/Storybook/ListContained'
import {atoms as a, ThemeProvider, useTheme} from '#/alf' import {atoms as a, ThemeProvider, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button' import {Button, ButtonText} from '#/components/Button'
import * as Layout from '#/components/Layout'
import {Admonitions} from './Admonitions' import {Admonitions} from './Admonitions'
import {Breakpoints} from './Breakpoints' import {Breakpoints} from './Breakpoints'
import {Buttons} from './Buttons' import {Buttons} from './Buttons'
@@ -21,12 +22,16 @@ import {Theming} from './Theming'
import {Typography} from './Typography' import {Typography} from './Typography'
export function Storybook() { export function Storybook() {
if (isWeb) return <StorybookInner />
return ( return (
<ScrollView> <Layout.Screen>
<StorybookInner /> {isWeb ? (
</ScrollView> <StorybookInner />
) : (
<ScrollView>
<StorybookInner />
</ScrollView>
)}
</Layout.Screen>
) )
} }
+15 -14
View File
@@ -1,17 +1,18 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {msg, Trans} from '@lingui/macro'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from 'view/com/util/Link'
import {CenteredView} from 'view/com/util/Views'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {HELP_DESK_URL} from 'lib/constants'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {HELP_DESK_URL} from '#/lib/constants'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {TextLink} from '#/view/com/util/Link'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'Support'>
export const SupportScreen = (_props: Props) => { export const SupportScreen = (_props: Props) => {
@@ -26,7 +27,7 @@ export const SupportScreen = (_props: Props) => {
) )
return ( return (
<View> <Layout.Screen>
<ViewHeader title={_(msg`Support`)} /> <ViewHeader title={_(msg`Support`)} />
<CenteredView> <CenteredView>
<Text type="title-xl" style={[pal.text, s.p20, s.pb5]}> <Text type="title-xl" style={[pal.text, s.p20, s.pb5]}>
@@ -44,6 +45,6 @@ export const SupportScreen = (_props: Props) => {
</Trans> </Trans>
</Text> </Text>
</CenteredView> </CenteredView>
</View> </Layout.Screen>
) )
} }
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react' import React from 'react'
import {View} from 'react-native' import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native' import {msg, Trans} from '@lingui/macro'
import {Text} from 'view/com/util/text/Text'
import {TextLink} from 'view/com/util/Link'
import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from 'view/com/util/Views'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {TextLink} from '#/view/com/util/Link'
import {Text} from '#/view/com/util/text/Text'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'TermsOfService'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'TermsOfService'>
export const TermsOfServiceScreen = (_props: Props) => { export const TermsOfServiceScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const TermsOfServiceScreen = (_props: Props) => {
) )
return ( return (
<View> <Layout.Screen>
<ViewHeader title={_(msg`Terms of Service`)} /> <ViewHeader title={_(msg`Terms of Service`)} />
<ScrollView style={[s.hContentRegion, pal.view]}> <ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}> <View style={[s.p20]}>
@@ -40,6 +42,6 @@ export const TermsOfServiceScreen = (_props: Props) => {
</View> </View>
<View style={s.footerSpacer} /> <View style={s.footerSpacer} />
</ScrollView> </ScrollView>
</View> </Layout.Screen>
) )
} }
+9 -19
View File
@@ -1,14 +1,7 @@
import React from 'react' import React from 'react'
import { import {BackHandler, StyleSheet, useWindowDimensions, View} from 'react-native'
BackHandler,
DimensionValue,
StyleSheet,
useWindowDimensions,
View,
} from 'react-native'
import {Drawer} from 'react-native-drawer-layout' import {Drawer} from 'react-native-drawer-layout'
import Animated from 'react-native-reanimated' import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import * as NavigationBar from 'expo-navigation-bar' import * as NavigationBar from 'expo-navigation-bar'
import {StatusBar} from 'expo-status-bar' import {StatusBar} from 'expo-status-bar'
import {useNavigation, useNavigationState} from '@react-navigation/native' import {useNavigation, useNavigationState} from '@react-navigation/native'
@@ -32,6 +25,7 @@ import {useCloseAnyActiveElement} from '#/state/util'
import {Lightbox} from '#/view/com/lightbox/Lightbox' import {Lightbox} from '#/view/com/lightbox/Lightbox'
import {ModalsContainer} from '#/view/com/modals/Modal' import {ModalsContainer} from '#/view/com/modals/Modal'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary' import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
import {atoms as a} from '#/alf'
import {MutedWordsDialog} from '#/components/dialogs/MutedWords' import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
import {SigninDialog} from '#/components/dialogs/Signin' import {SigninDialog} from '#/components/dialogs/Signin'
import {Outlet as PortalOutlet} from '#/components/Portal' import {Outlet as PortalOutlet} from '#/components/Portal'
@@ -46,11 +40,7 @@ function ShellInner() {
const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled() const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled()
const setIsDrawerOpen = useSetDrawerOpen() const setIsDrawerOpen = useSetDrawerOpen()
const winDim = useWindowDimensions() const winDim = useWindowDimensions()
const safeAreaInsets = useSafeAreaInsets()
const containerPadding = React.useMemo(
() => ({height: '100%' as DimensionValue, paddingTop: safeAreaInsets.top}),
[safeAreaInsets],
)
const renderDrawerContent = React.useCallback(() => <DrawerContent />, []) const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
const onOpenDrawer = React.useCallback( const onOpenDrawer = React.useCallback(
() => setIsDrawerOpen(true), () => setIsDrawerOpen(true),
@@ -68,14 +58,14 @@ function ShellInner() {
useNotificationsHandler() useNotificationsHandler()
React.useEffect(() => { React.useEffect(() => {
let listener = {remove() {}}
if (isAndroid) { if (isAndroid) {
listener = BackHandler.addEventListener('hardwareBackPress', () => { const listener = BackHandler.addEventListener('hardwareBackPress', () => {
return closeAnyActiveElement() return closeAnyActiveElement()
}) })
}
return () => { return () => {
listener.remove() listener.remove()
}
} }
}, [closeAnyActiveElement]) }, [closeAnyActiveElement])
@@ -102,7 +92,7 @@ function ShellInner() {
return ( return (
<> <>
<Animated.View style={containerPadding}> <Animated.View style={[a.h_full]}>
<ErrorBoundary> <ErrorBoundary>
<Drawer <Drawer
renderDrawerContent={renderDrawerContent} renderDrawerContent={renderDrawerContent}
+8 -7
View File
@@ -7,19 +7,20 @@ import {useNavigation} from '@react-navigation/native'
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {useIntentHandler} from '#/lib/hooks/useIntentHandler' import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {NavigationProp} from '#/lib/routes/types' import {NavigationProp} from '#/lib/routes/types'
import {colors, s} from '#/lib/styles' import {colors} from '#/lib/styles'
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut' import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut'
import {useCloseAllActiveElements} from '#/state/util' import {useCloseAllActiveElements} from '#/state/util'
import {Lightbox} from '#/view/com/lightbox/Lightbox'
import {ModalsContainer} from '#/view/com/modals/Modal'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
import {atoms as a} from '#/alf'
import {MutedWordsDialog} from '#/components/dialogs/MutedWords' import {MutedWordsDialog} from '#/components/dialogs/MutedWords'
import {SigninDialog} from '#/components/dialogs/Signin' import {SigninDialog} from '#/components/dialogs/Signin'
import {Outlet as PortalOutlet} from '#/components/Portal' import {Outlet as PortalOutlet} from '#/components/Portal'
import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries' import {FlatNavigator, RoutesContainer} from '#/Navigation'
import {FlatNavigator, RoutesContainer} from '../../Navigation'
import {Lightbox} from '../com/lightbox/Lightbox'
import {ModalsContainer} from '../com/modals/Modal'
import {ErrorBoundary} from '../com/util/ErrorBoundary'
import {Composer} from './Composer.web' import {Composer} from './Composer.web'
import {DrawerContent} from './Drawer' import {DrawerContent} from './Drawer'
@@ -78,7 +79,7 @@ function ShellInner() {
export const Shell: React.FC = function ShellImpl() { export const Shell: React.FC = function ShellImpl() {
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark) const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
return ( return (
<View style={[s.hContentRegion, pageBg]}> <View style={[a.util_screen_outer, pageBg]}>
<RoutesContainer> <RoutesContainer>
<ShellInner /> <ShellInner />
</RoutesContainer> </RoutesContainer>