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 {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebScrollRestoration} from '#/lib/hooks/useWebScrollRestoration'
import {buildStateObject} from '#/lib/routes/helpers'
import {
@@ -93,6 +92,7 @@ import {
StarterPackScreenShort,
} from '#/screens/StarterPack/StarterPackScreen'
import {Wizard} from '#/screens/StarterPack/Wizard'
import {useTheme} from '#/alf'
import {router} from '#/routes'
import {Referrer} from '../modules/expo-bluesky-swiss-army'
@@ -412,7 +412,7 @@ function TabsNavigator() {
}
function HomeTabNavigator() {
const pal = usePalette('default')
const t = useTheme()
return (
<HomeTab.Navigator
@@ -422,7 +422,7 @@ function HomeTabNavigator() {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<HomeTab.Screen name="Home" getComponent={() => HomeScreen} />
<HomeTab.Screen name="Start" getComponent={() => HomeScreen} />
@@ -432,7 +432,7 @@ function HomeTabNavigator() {
}
function SearchTabNavigator() {
const pal = usePalette('default')
const t = useTheme()
return (
<SearchTab.Navigator
screenOptions={{
@@ -441,7 +441,7 @@ function SearchTabNavigator() {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<SearchTab.Screen name="Search" getComponent={() => SearchScreen} />
{commonScreens(SearchTab as typeof HomeTab)}
@@ -450,7 +450,7 @@ function SearchTabNavigator() {
}
function NotificationsTabNavigator() {
const pal = usePalette('default')
const t = useTheme()
return (
<NotificationsTab.Navigator
screenOptions={{
@@ -459,7 +459,7 @@ function NotificationsTabNavigator() {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<NotificationsTab.Screen
name="Notifications"
@@ -472,7 +472,7 @@ function NotificationsTabNavigator() {
}
function MyProfileTabNavigator() {
const pal = usePalette('default')
const t = useTheme()
return (
<MyProfileTab.Navigator
screenOptions={{
@@ -481,7 +481,7 @@ function MyProfileTabNavigator() {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<MyProfileTab.Screen
// @ts-ignore // TODO: fix this broken type in ProfileScreen
@@ -498,7 +498,7 @@ function MyProfileTabNavigator() {
}
function MessagesTabNavigator() {
const pal = usePalette('default')
const t = useTheme()
return (
<MessagesTab.Navigator
screenOptions={{
@@ -507,7 +507,7 @@ function MessagesTabNavigator() {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<MessagesTab.Screen
name="Messages"
@@ -527,7 +527,7 @@ function MessagesTabNavigator() {
* in a single ("flat") stack.
*/
const FlatNavigator = () => {
const pal = usePalette('default')
const t = useTheme()
const numUnread = useUnreadNotifications()
const screenListeners = useWebScrollRestoration()
const title = (page: MessageDescriptor) => bskyTitle(i18n._(page), numUnread)
@@ -541,7 +541,7 @@ const FlatNavigator = () => {
gestureEnabled: true,
fullScreenGestureEnabled: true,
headerShown: false,
contentStyle: pal.view,
contentStyle: t.atoms.bg,
}}>
<Flat.Screen
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 {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 {Button, ButtonText} from '#/components/Button'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography'
import {SharedPrefs} from '../../../modules/expo-bluesky-swiss-army'
@@ -11,103 +12,105 @@ export function SharedPreferencesTesterScreen() {
const [currentTestOutput, setCurrentTestOutput] = React.useState<string>('')
return (
<ScrollView contentContainerStyle={{backgroundColor: 'red'}}>
<View style={[a.flex_1]}>
<View>
<Text testID="testOutput">{currentTestOutput}</Text>
<Layout.Screen>
<ScrollView contentContainerStyle={{backgroundColor: 'red'}}>
<View style={[a.flex_1]}>
<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 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>
</ScrollView>
</ScrollView>
</Layout.Screen>
)
}
+16 -15
View File
@@ -6,23 +6,24 @@ import {useLingui} from '@lingui/react'
import {useFocusEffect} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {HITSLOP_10} from 'lib/constants'
import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams} from 'lib/routes/types'
import {shareUrl} from 'lib/sharing'
import {cleanError} from 'lib/strings/errors'
import {sanitizeHandle} from 'lib/strings/handles'
import {enforceLen} from 'lib/strings/helpers'
import {isNative, isWeb} from 'platform/detection'
import {useSearchPostsQuery} from 'state/queries/search-posts'
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from 'state/shell'
import {HITSLOP_10} from '#/lib/constants'
import {useInitialNumToRender} from '#/lib/hooks/useInitialNumToRender'
import {CommonNavigatorParams} from '#/lib/routes/types'
import {shareUrl} from '#/lib/sharing'
import {cleanError} from '#/lib/strings/errors'
import {sanitizeHandle} from '#/lib/strings/handles'
import {enforceLen} from '#/lib/strings/helpers'
import {isNative, isWeb} from '#/platform/detection'
import {useSearchPostsQuery} from '#/state/queries/search-posts'
import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell'
import {Pager} from '#/view/com/pager/Pager'
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 {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 * as Layout from '#/components/Layout'
import {ListFooter, ListMaybePlaceholder} from '#/components/Lists'
const renderItem = ({item}: ListRenderItemInfo<PostView>) => {
@@ -108,7 +109,7 @@ export default function HashtagScreen({
}, [_, fullTag, author, activeTab])
return (
<>
<Layout.Screen>
<CenteredView sideBorders={true}>
<ViewHeader
showOnDesktop
@@ -155,7 +156,7 @@ export default function HashtagScreen({
<View key={i}>{section.component}</View>
))}
</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 {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {SettingsSliderVertical_Stroke2_Corner0_Rounded as SettingsSlider} from '#/components/icons/SettingsSlider'
import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {ListFooter} from '#/components/Lists'
import {Loader} from '#/components/Loader'
@@ -149,7 +150,7 @@ export function MessagesScreen({navigation, route}: Props) {
if (conversations.length < 1) {
return (
<View style={a.flex_1}>
<Layout.Screen>
<CenteredView sideBorders={gtMobile} style={[a.h_full_vh]}>
{gtMobile ? (
<DesktopHeader
@@ -231,12 +232,12 @@ export function MessagesScreen({navigation, route}: Props) {
{!isLoading && !isError && (
<NewChat onNewChat={onNewChat} control={newChatControl} />
)}
</View>
</Layout.Screen>
)
}
return (
<View style={a.flex_1}>
<Layout.Screen testID="messagesScreen">
{!gtMobile && (
<ViewHeader
title={_(msg`Messages`)}
@@ -276,7 +277,7 @@ export function MessagesScreen({navigation, route}: Props) {
// @ts-ignore our .web version only -sfn
desktopFixedHeight
/>
</View>
</Layout.Screen>
)
}
+8 -5
View File
@@ -18,10 +18,11 @@ import {useProfileQuery} from '#/state/queries/profile'
import {useSetMinimalShellMode} from '#/state/shell'
import {CenteredView} from '#/view/com/util/Views'
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 {MessagesListHeader} from '#/components/dms/MessagesListHeader'
import {Error} from '#/components/Error'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
type Props = NativeStackScreenProps<
@@ -64,9 +65,11 @@ export function MessagesConversationScreen({route}: Props) {
)
return (
<ConvoProvider key={convoId} convoId={convoId}>
<Inner />
</ConvoProvider>
<Layout.Screen testID="convoScreen" style={web([{minHeight: 0}, a.flex_1])}>
<ConvoProvider key={convoId} convoId={convoId}>
<Inner />
</ConvoProvider>
</Layout.Screen>
)
}
@@ -100,7 +103,7 @@ function Inner() {
if (convoState.status === ConvoStatus.Error) {
return (
<CenteredView style={a.flex_1} sideBorders>
<CenteredView style={[a.flex_1]} sideBorders>
<MessagesListHeader />
<Error
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 {Divider} from '#/components/Divider'
import * as Toggle from '#/components/forms/Toggle'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography'
import {useBackgroundNotificationPreferences} from '../../../modules/expo-background-notification-handler/src/BackgroundNotificationHandlerProvider'
@@ -55,91 +56,93 @@ export function MessagesSettingsScreen({}: Props) {
)
return (
<ScrollView stickyHeaderIndices={[0]}>
<ViewHeader title={_(msg`Chat Settings`)} showOnDesktop showBorder />
<View style={[a.p_lg, a.gap_md]}>
<Text style={[a.text_lg, a.font_bold]}>
<Trans>Allow new messages from</Trans>
</Text>
<Toggle.Group
label={_(msg`Allow new messages from`)}
type="radio"
values={[
(profile?.associated?.chat?.allowIncoming as AllowIncoming) ??
'following',
]}
onChange={onSelectMessagesFrom}>
<View>
<Toggle.Item
name="all"
label={_(msg`Everyone`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Everyone</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="following"
label={_(msg`Users I follow`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Users I follow</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="none"
label={_(msg`No one`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>No one</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
</View>
</Toggle.Group>
<Admonition type="tip">
<Trans>
You can continue ongoing conversations regardless of which setting
you choose.
</Trans>
</Admonition>
{isNative && (
<>
<Divider style={a.my_md} />
<Text style={[a.text_lg, a.font_bold]}>
<Trans>Notification Sounds</Trans>
</Text>
<Toggle.Group
label={_(msg`Notification sounds`)}
type="radio"
values={[preferences.playSoundChat ? 'enabled' : 'disabled']}
onChange={onSelectSoundSetting}>
<View>
<Toggle.Item
name="enabled"
label={_(msg`Enabled`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Enabled</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="disabled"
label={_(msg`Disabled`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Disabled</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
</View>
</Toggle.Group>
</>
)}
</View>
</ScrollView>
<Layout.Screen testID="messagesSettingsScreen">
<ScrollView stickyHeaderIndices={[0]}>
<ViewHeader title={_(msg`Chat Settings`)} showOnDesktop showBorder />
<View style={[a.p_lg, a.gap_md]}>
<Text style={[a.text_lg, a.font_bold]}>
<Trans>Allow new messages from</Trans>
</Text>
<Toggle.Group
label={_(msg`Allow new messages from`)}
type="radio"
values={[
(profile?.associated?.chat?.allowIncoming as AllowIncoming) ??
'following',
]}
onChange={onSelectMessagesFrom}>
<View>
<Toggle.Item
name="all"
label={_(msg`Everyone`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Everyone</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="following"
label={_(msg`Users I follow`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Users I follow</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="none"
label={_(msg`No one`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>No one</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
</View>
</Toggle.Group>
<Admonition type="tip">
<Trans>
You can continue ongoing conversations regardless of which setting
you choose.
</Trans>
</Admonition>
{isNative && (
<>
<Divider style={a.my_md} />
<Text style={[a.text_lg, a.font_bold]}>
<Trans>Notification Sounds</Trans>
</Text>
<Toggle.Group
label={_(msg`Notification sounds`)}
type="radio"
values={[preferences.playSoundChat ? 'enabled' : 'disabled']}
onChange={onSelectSoundSetting}>
<View>
<Toggle.Item
name="enabled"
label={_(msg`Enabled`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Enabled</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
<Toggle.Item
name="disabled"
label={_(msg`Disabled`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Disabled</Trans>
</Toggle.LabelText>
<Toggle.Radio />
</Toggle.Item>
</View>
</Toggle.Group>
</>
)}
</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 {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person'
import * as LabelingService from '#/components/LabelingServiceCard'
import * as Layout from '#/components/Layout'
import {InlineLinkText, Link} from '#/components/Link'
import {Loader} from '#/components/Loader'
import {GlobalLabelPreference} from '#/components/moderation/LabelPreference'
@@ -94,31 +95,33 @@ export function ModerationScreen(
const error = preferencesError
return (
<CenteredView
testID="moderationScreen"
style={[
t.atoms.border_contrast_low,
t.atoms.bg,
{minHeight: height},
...(gtMobile ? [a.border_l, a.border_r] : []),
]}>
<ViewHeader title={_(msg`Moderation`)} showOnDesktop />
<Layout.Screen testID="moderationScreen">
<CenteredView
testID="moderationScreen"
style={[
t.atoms.border_contrast_low,
t.atoms.bg,
{minHeight: height},
...(gtMobile ? [a.border_l, a.border_r] : []),
]}>
<ViewHeader title={_(msg`Moderation`)} showOnDesktop />
{isLoading ? (
<View style={[a.w_full, a.align_center, a.pt_2xl]}>
<Loader size="xl" fill={t.atoms.text.color} />
</View>
) : error || !preferences ? (
<ErrorState
error={
preferencesError?.toString() ||
_(msg`Something went wrong, please try again.`)
}
/>
) : (
<ModerationScreenInner preferences={preferences} />
)}
</CenteredView>
{isLoading ? (
<View style={[a.w_full, a.align_center, a.pt_2xl]}>
<Loader size="xl" fill={t.atoms.text.color} />
</View>
) : error || !preferences ? (
<ErrorState
error={
preferencesError?.toString() ||
_(msg`Something went wrong, please try again.`)
}
/>
) : (
<ModerationScreenInner preferences={preferences} />
)}
</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 {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import {atoms as a} from '#/alf'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostLikedBy'>
@@ -27,10 +27,12 @@ export const PostLikedByScreen = ({route}: Props) => {
)
return (
<CenteredView style={a.util_screen_outer} sideBorders={true}>
<ListHeaderDesktop title={_(msg`Liked By`)} />
<ViewHeader title={_(msg`Liked By`)} showBorder={!isWeb} />
<PostLikedByComponent uri={uri} />
</CenteredView>
<Layout.Screen>
<CenteredView sideBorders={true}>
<ListHeaderDesktop title={_(msg`Liked By`)} />
<ViewHeader title={_(msg`Liked By`)} showBorder={!isWeb} />
<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 {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostQuotes as PostQuotesComponent} from '#/view/com/post-thread/PostQuotes'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import {atoms as a} from '#/alf'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostQuotes'>
@@ -27,10 +27,12 @@ export const PostQuotesScreen = ({route}: Props) => {
)
return (
<CenteredView style={a.util_screen_outer} sideBorders={true}>
<ListHeaderDesktop title={_(msg`Quotes`)} />
<ViewHeader title={_(msg`Quotes`)} showBorder={!isWeb} />
<PostQuotesComponent uri={uri} />
</CenteredView>
<Layout.Screen>
<CenteredView sideBorders={true}>
<ListHeaderDesktop title={_(msg`Quotes`)} />
<ViewHeader title={_(msg`Quotes`)} showBorder={!isWeb} />
<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 {makeRecordUri} from '#/lib/strings/url-helpers'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {isWeb} from 'platform/detection'
import {PostRepostedBy as PostRepostedByComponent} from '#/view/com/post-thread/PostRepostedBy'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import {atoms as a} from '#/alf'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostRepostedBy'>
@@ -27,10 +27,12 @@ export const PostRepostedByScreen = ({route}: Props) => {
)
return (
<CenteredView style={a.util_screen_outer} sideBorders={true}>
<ListHeaderDesktop title={_(msg`Reposted By`)} />
<ViewHeader title={_(msg`Reposted By`)} showBorder={!isWeb} />
<PostRepostedByComponent uri={uri} />
</CenteredView>
<Layout.Screen>
<CenteredView sideBorders={true}>
<ListHeaderDesktop title={_(msg`Reposted By`)} />
<ViewHeader title={_(msg`Reposted By`)} showBorder={!isWeb} />
<PostRepostedByComponent uri={uri} />
</CenteredView>
</Layout.Screen>
)
}
+15 -13
View File
@@ -1,20 +1,20 @@
import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
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 {logger} from '#/logger'
import {useProfileKnownFollowersQuery} from '#/state/queries/known-followers'
import {useResolveDidQuery} from '#/state/queries/resolve-uri'
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 {List} from '#/view/com/util/List'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
import {
ListFooter,
ListHeaderDesktop,
@@ -92,19 +92,21 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
if (followers.length < 1) {
return (
<ListMaybePlaceholder
isLoading={isDidLoading || isFollowersLoading}
isError={isError}
emptyType="results"
emptyMessage={_(msg`You don't follow any users who follow @${name}.`)}
errorMessage={cleanError(resolveError || error)}
onRetry={isError ? refetch : undefined}
/>
<Layout.Screen>
<ListMaybePlaceholder
isLoading={isDidLoading || isFollowersLoading}
isError={isError}
emptyType="results"
emptyMessage={_(msg`You don't follow any users who follow @${name}.`)}
errorMessage={cleanError(resolveError || error)}
onRetry={isError ? refetch : undefined}
/>
</Layout.Screen>
)
}
return (
<View style={{flex: 1}}>
<Layout.Screen>
<ViewHeader title={_(msg`Followers you know`)} />
<List
data={followers}
@@ -129,6 +131,6 @@ export const ProfileKnownFollowersScreen = ({route}: Props) => {
initialNumToRender={initialNumToRender}
windowSize={11}
/>
</View>
</Layout.Screen>
)
}
@@ -1,5 +1,4 @@
import React from 'react'
import {View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
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 {useSetMinimalShellMode} from '#/state/shell'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
import {LikedByList} from '#/components/LikedByList'
export function ProfileLabelerLikedByScreen({
@@ -25,9 +25,9 @@ export function ProfileLabelerLikedByScreen({
)
return (
<View style={{flex: 1}}>
<Layout.Screen>
<ViewHeader title={_(msg`Liked By`)} />
<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 {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetThemePrefs, useThemePrefs} from '#/state/shell'
import {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
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 {TextSize_Stroke2_Corner0_Rounded as TextSize} from '#/components/icons/TextSize'
import {TitleCase_Stroke2_Corner0_Rounded as Aa} from '#/components/icons/TitleCase'
import * as Layout from '#/components/Layout'
import {Text} from '#/components/Typography'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppearanceSettings'>
@@ -76,7 +76,7 @@ export function AppearanceSettingsScreen({}: Props) {
return (
<LayoutAnimationConfig skipExiting skipEntering>
<View testID="preferencesThreadsScreen" style={s.hContentRegion}>
<Layout.Screen testID="preferencesThreadsScreen">
<ScrollView
// @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}}
@@ -180,7 +180,7 @@ export function AppearanceSettingsScreen({}: Props) {
</View>
</View>
</ScrollView>
</View>
</Layout.Screen>
</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 {Pencil_Stroke2_Corner0_Rounded as Pencil} from '#/components/icons/Pencil'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import * as Layout from '#/components/Layout'
import {ListMaybePlaceholder} from '#/components/Lists'
import {Loader} from '#/components/Loader'
import * as Menu from '#/components/Menu'
@@ -76,7 +77,11 @@ type StarterPackScreenShortProps = NativeStackScreenProps<
>
export function StarterPackScreen({route}: StarterPackScreeProps) {
return <StarterPackScreenInner routeParams={route.params} />
return (
<Layout.Screen>
<StarterPackScreenInner routeParams={route.params} />
</Layout.Screen>
)
}
export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
@@ -91,15 +96,21 @@ export function StarterPackScreenShort({route}: StarterPackScreenShortProps) {
if (isLoading || isError || !resolvedStarterPack) {
return (
<ListMaybePlaceholder
isLoading={isLoading}
isError={isError}
errorMessage={_(msg`That starter pack could not be found.`)}
emptyMessage={_(msg`That starter pack could not be found.`)}
/>
<Layout.Screen>
<ListMaybePlaceholder
isLoading={isLoading}
isError={isError}
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({
+45 -38
View File
@@ -19,32 +19,32 @@ import {useLingui} from '@lingui/react'
import {useFocusEffect, useNavigation} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
import {logger} from '#/logger'
import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from 'lib/constants'
import {createSanitizedDisplayName} from 'lib/moderation/create-sanitized-display-name'
import {CommonNavigatorParams, NavigationProp} from 'lib/routes/types'
import {logEvent} from 'lib/statsig/statsig'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {enforceLen} from 'lib/strings/helpers'
import {HITSLOP_10, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
import {createSanitizedDisplayName} from '#/lib/moderation/create-sanitized-display-name'
import {CommonNavigatorParams, NavigationProp} from '#/lib/routes/types'
import {logEvent} from '#/lib/statsig/statsig'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {enforceLen} from '#/lib/strings/helpers'
import {
getStarterPackOgCard,
parseStarterPackUri,
} from 'lib/strings/starter-pack'
import {isAndroid, isNative, isWeb} from 'platform/detection'
import {useModerationOpts} from 'state/preferences/moderation-opts'
import {useAllListMembersQuery} from 'state/queries/list-members'
import {useProfileQuery} from 'state/queries/profile'
} from '#/lib/strings/starter-pack'
import {logger} from '#/logger'
import {isAndroid, isNative, isWeb} from '#/platform/detection'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useAllListMembersQuery} from '#/state/queries/list-members'
import {useProfileQuery} from '#/state/queries/profile'
import {
useCreateStarterPackMutation,
useEditStarterPackMutation,
useStarterPackQuery,
} from 'state/queries/starter-packs'
import {useSession} from 'state/session'
import {useSetMinimalShellMode} from 'state/shell'
} from '#/state/queries/starter-packs'
import {useSession} from '#/state/session'
import {useSetMinimalShellMode} from '#/state/shell'
import * as Toast from '#/view/com/util/Toast'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {CenteredView} from 'view/com/util/Views'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {CenteredView} from '#/view/com/util/Views'
import {useWizardState, WizardStep} from '#/screens/StarterPack/Wizard/State'
import {StepDetails} from '#/screens/StarterPack/Wizard/StepDetails'
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 {Button, ButtonText} from '#/components/Button'
import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import {ListMaybePlaceholder} from '#/components/Lists'
import {Loader} from '#/components/Loader'
import {WizardEditListDialog} from '#/components/StarterPack/Wizard/WizardEditListDialog'
@@ -97,33 +98,39 @@ export function Wizard({
if (!isReady) {
return (
<ListMaybePlaceholder
isLoading={
isLoadingStarterPack || isLoadingProfiles || isLoadingProfile
}
isError={isErrorStarterPack || isErrorProfiles || isErrorProfile}
errorMessage={_(msg`That starter pack could not be found.`)}
/>
<Layout.Screen>
<ListMaybePlaceholder
isLoading={
isLoadingStarterPack || isLoadingProfiles || isLoadingProfile
}
isError={isErrorStarterPack || isErrorProfiles || isErrorProfile}
errorMessage={_(msg`That starter pack could not be found.`)}
/>
</Layout.Screen>
)
} else if (isEdit && starterPack?.creator.did !== currentAccount?.did) {
return (
<ListMaybePlaceholder
isLoading={false}
isError={true}
errorMessage={_(msg`That starter pack could not be found.`)}
/>
<Layout.Screen>
<ListMaybePlaceholder
isLoading={false}
isError={true}
errorMessage={_(msg`That starter pack could not be found.`)}
/>
</Layout.Screen>
)
}
return (
<Provider starterPack={starterPack} listItems={listItems}>
<WizardInner
currentStarterPack={starterPack}
currentListItems={listItems}
profile={profile}
moderationOpts={moderationOpts}
/>
</Provider>
<Layout.Screen>
<Provider starterPack={starterPack} listItems={listItems}>
<WizardInner
currentStarterPack={starterPack}
currentListItems={listItems}
profile={profile}
moderationOpts={moderationOpts}
/>
</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 {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -54,7 +55,7 @@ export function AccessibilitySettingsScreen({}: Props) {
)
return (
<View style={s.hContentRegion} testID="accessibilitySettingsScreen">
<Layout.Screen testID="accessibilitySettingsScreen">
<SimpleViewHeader
showBackButton={isTabletOrMobile}
style={[
@@ -128,7 +129,7 @@ export function AccessibilitySettingsScreen({}: Props) {
</>
)}
</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 {atoms as a} from '#/alf'
import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import * as Prompt from '#/components/Prompt'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
export function AppPasswords({}: Props) {
return (
<Layout.Screen testID="AppPasswordsScreen">
<AppPasswordsInner />
</Layout.Screen>
)
}
function AppPasswordsInner() {
const pal = usePalette('default')
const {_} = useLingui()
const setMinimalShellMode = useSetMinimalShellMode()
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react'
import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
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 {msg, Trans} from '@lingui/macro'
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,
@@ -28,7 +30,7 @@ export const CommunityGuidelinesScreen = (_props: Props) => {
)
return (
<View>
<Layout.Screen>
<ViewHeader title={_(msg`Community Guidelines`)} />
<ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}>
@@ -45,6 +47,6 @@ export const CommunityGuidelinesScreen = (_props: Props) => {
</View>
<View style={s.footerSpacer} />
</ScrollView>
</View>
</Layout.Screen>
)
}
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react'
import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
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 {msg, Trans} from '@lingui/macro'
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'>
export const CopyrightPolicyScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const CopyrightPolicyScreen = (_props: Props) => {
)
return (
<View>
<Layout.Screen>
<ViewHeader title={_(msg`Copyright Policy`)} />
<ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}>
@@ -42,6 +44,6 @@ export const CopyrightPolicyScreen = (_props: Props) => {
</View>
<View style={s.footerSpacer} />
</ScrollView>
</View>
</Layout.Screen>
)
}
+27 -20
View File
@@ -1,24 +1,29 @@
import React from 'react'
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 {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']
export const DebugScreen = ({}: NativeStackScreenProps<
@@ -33,10 +38,12 @@ export const DebugScreen = ({}: NativeStackScreenProps<
}
return (
<ThemeProvider theme={colorScheme}>
<DebugInner
colorScheme={colorScheme}
onToggleColorScheme={onToggleColorScheme}
/>
<Layout.Screen>
<DebugInner
colorScheme={colorScheme}
onToggleColorScheme={onToggleColorScheme}
/>
</Layout.Screen>
</ThemeProvider>
)
}
+293 -276
View File
@@ -21,6 +21,7 @@ import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {moderationOptsOverrideContext} from '#/state/preferences/moderation-opts'
import {FeedNotification} from '#/state/queries/notifications/types'
import {
@@ -28,7 +29,6 @@ import {
shouldFilterNotif,
} from '#/state/queries/notifications/util'
import {useSession} from '#/state/session'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {CenteredView, ScrollView} from '#/view/com/util/Views'
import {ProfileHeaderStandard} from '#/screens/Profile/Header/ProfileHeaderStandard'
import {atoms as a, useTheme} from '#/alf'
@@ -41,6 +41,7 @@ import {
ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottom,
ChevronTop_Stroke2_Corner0_Rounded as ChevronTop,
} from '#/components/icons/Chevron'
import * as Layout from '#/components/Layout'
import {H1, H3, P, Text} from '#/components/Typography'
import {ScreenHider} from '../../components/moderation/ScreenHider'
import {FeedItem as NotifFeedItem} from '../com/notifications/FeedItem'
@@ -264,309 +265,325 @@ export const DebugModScreen = ({}: NativeStackScreenProps<
}, [post, modOpts])
return (
<moderationOptsOverrideContext.Provider value={modOpts}>
<ScrollView>
<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>
<Layout.Screen>
<moderationOptsOverrideContext.Provider value={modOpts}>
<ScrollView>
<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" />
<ToggleButton.Group
label="Scenario"
values={scenario}
onChange={setScenario}>
<ToggleButton.Button name="label" label="Label">
<ToggleButton.ButtonText>Label</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="block" label="Block">
<ToggleButton.ButtonText>Block</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="mute" label="Mute">
<ToggleButton.ButtonText>Mute</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
<Heading title="" subtitle="Scenario" />
<ToggleButton.Group
label="Scenario"
values={scenario}
onChange={setScenario}>
<ToggleButton.Button name="label" label="Label">
<ToggleButton.ButtonText>Label</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="block" label="Block">
<ToggleButton.ButtonText>Block</ToggleButton.ButtonText>
</ToggleButton.Button>
<ToggleButton.Button name="mute" label="Mute">
<ToggleButton.ButtonText>Mute</ToggleButton.ButtonText>
</ToggleButton.Button>
</ToggleButton.Group>
{scenario[0] === 'label' && (
<>
<View
style={[
a.border,
a.rounded_sm,
a.mt_lg,
a.mb_lg,
a.p_lg,
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">
{scenario[0] === 'label' && (
<>
<View
style={[
a.border,
a.rounded_sm,
a.mt_lg,
a.mb_lg,
a.p_lg,
t.atoms.border_contrast_medium,
]}>
<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>
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>
{LABELS[label[0] as keyof typeof LABELS]?.configurable !==
false && (
<View style={[a.mt_md]}>
<Text
style={[a.font_bold, a.text_xs, t.atoms.text, a.pb_sm]}>
Preference
</Text>
<Toggle.Group
label="Preference"
type="radio"
values={visibility}
onChange={setVisiblity}>
<View
{label[0] === 'custom' ? (
<CustomLabelForm
def={customLabelDef}
setDef={setCustomLabelDef}
/>
) : (
<>
<View style={{height: 10}} />
<Divider />
</>
)}
<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={[
a.flex_row,
a.gap_md,
a.flex_wrap,
a.align_center,
a.font_bold,
a.text_xs,
t.atoms.text,
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.LabelText>Hide</Toggle.LabelText>
<Toggle.LabelText>Account</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="warn" label="Warn">
<Toggle.Item name="profile" label="Profile">
<Toggle.Radio />
<Toggle.LabelText>Warn</Toggle.LabelText>
<Toggle.LabelText>Profile</Toggle.LabelText>
</Toggle.Item>
<Toggle.Item name="ignore" label="Ignore">
<Toggle.Item name="post" label="Post">
<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>
</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.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>
</>
)}
<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' && (
<>
<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} />
</>
)}
<Spacer />
{view[0] === 'account' && (
<>
<Heading title="Account" subtitle="in listing" />
<MockAccountCard
profile={profile}
moderation={profileModeration}
/>
<Heading title="" subtitle="Results" />
<Heading title="Account" subtitle="viewing directly" />
<MockAccountScreen
profile={profile}
moderation={profileModeration}
moderationOpts={modOpts}
/>
</>
)}
<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[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={[
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} />
<View style={{height: 400}} />
</CenteredView>
</ScrollView>
</moderationOptsOverrideContext.Provider>
<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' && (
<>
<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 {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
import * as Layout from '#/components/Layout'
import * as ListCard from '#/components/ListCard'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Feeds'>
@@ -545,7 +546,7 @@ export function FeedsScreen(_props: Props) {
)
return (
<View style={[pal.view, styles.container]}>
<Layout.Screen testID="FeedsScreen">
{isMobile && (
<ViewHeader
title={_(msg`Feeds`)}
@@ -582,7 +583,7 @@ export function FeedsScreen(_props: Props) {
accessibilityHint=""
/>
)}
</View>
</Layout.Screen>
)
}
@@ -768,9 +769,6 @@ function FeedsAboutHeader() {
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
list: {
height: '100%',
},
+12 -9
View File
@@ -1,5 +1,5 @@
import React from 'react'
import {ActivityIndicator, StyleSheet, View} from 'react-native'
import {ActivityIndicator, StyleSheet} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
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 {useSelectedFeed, useSetSelectedFeed} from '#/state/shell/selected-feed'
import {FeedPage} from '#/view/com/feeds/FeedPage'
import {HomeHeader} from '#/view/com/home/HomeHeader'
import {Pager, PagerRef, RenderTabBarFnProps} from '#/view/com/pager/Pager'
import {CustomFeedEmptyState} from '#/view/com/posts/CustomFeedEmptyState'
import {FollowingEmptyState} from '#/view/com/posts/FollowingEmptyState'
import {FollowingEndOfFeed} from '#/view/com/posts/FollowingEndOfFeed'
import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
import {HomeHeader} from '../com/home/HomeHeader'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'>
export function HomeScreen(props: Props) {
@@ -70,17 +71,19 @@ export function HomeScreen(props: Props) {
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
return (
<HomeScreenReady
{...props}
preferences={preferences}
pinnedFeedInfos={pinnedFeedInfos}
/>
<Layout.Screen testID="HomeScreen">
<HomeScreenReady
{...props}
preferences={preferences}
pinnedFeedInfos={pinnedFeedInfos}
/>
</Layout.Screen>
)
} else {
return (
<View style={styles.loading}>
<Layout.Screen style={styles.loading}>
<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 {useSetMinimalShellMode} from '#/state/shell'
import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
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'>
@@ -76,232 +77,234 @@ export function LanguageSettingsScreen(_props: Props) {
}, [langPrefs.contentLanguages])
return (
<CenteredView
style={[
pal.view,
pal.border,
styles.container,
isTabletOrDesktop && styles.desktopContainer,
]}>
<ViewHeader title={_(msg`Language Settings`)} showOnDesktop />
<Layout.Screen testID="PreferencesLanguagesScreen">
<CenteredView
style={[
pal.view,
pal.border,
styles.container,
isTabletOrDesktop && styles.desktopContainer,
]}>
<ViewHeader title={_(msg`Language Settings`)} showOnDesktop />
<View style={{paddingTop: 20, paddingHorizontal: 20}}>
{/* APP LANGUAGE */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<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`)}
<View style={{paddingTop: 20, paddingHorizontal: 20}}>
{/* APP LANGUAGE */}
<View style={{paddingBottom: 20}}>
<Text type="title-sm" style={[pal.text, s.pb5]}>
<Trans>App Language</Trans>
</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>
</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 {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'Lists'>
export function ListsScreen({}: Props) {
@@ -48,7 +49,7 @@ export function ListsScreen({}: Props) {
}, [openModal, navigation])
return (
<View style={s.hContentRegion} testID="listsScreen">
<Layout.Screen testID="listsScreen">
<SimpleViewHeader
showBackButton={isMobile}
style={[
@@ -86,6 +87,6 @@ export function ListsScreen({}: Props) {
</View>
</SimpleViewHeader>
<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 {useFocusEffect} from '@react-navigation/native'
import {usePalette} from '#/lib/hooks/usePalette'
import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {getEntries} from '#/logger/logDump'
import {useTickEveryMinute} from '#/state/shell'
import {useSetMinimalShellMode} from '#/state/shell'
import {usePalette} from 'lib/hooks/usePalette'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {s} from 'lib/styles'
import {Text} from '../com/util/text/Text'
import {ViewHeader} from '../com/util/ViewHeader'
import {ScrollView} from '../com/util/Views'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {ScrollView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
export function LogScreen({}: NativeStackScreenProps<
CommonNavigatorParams,
@@ -42,7 +43,7 @@ export function LogScreen({}: NativeStackScreenProps<
}
return (
<View style={[s.flex1]}>
<Layout.Screen>
<ViewHeader title="Log" />
<ScrollView style={s.flex1}>
{getEntries()
@@ -91,7 +92,7 @@ export function LogScreen({}: NativeStackScreenProps<
})}
<View style={s.footerSpacer} />
</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 {useSetMinimalShellMode} from '#/state/shell'
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 {ErrorScreen} from '../com/util/error/ErrorScreen'
import {Text} from '../com/util/text/Text'
import {ViewHeader} from '../com/util/ViewHeader'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -95,76 +96,78 @@ export function ModerationBlockedAccounts({}: Props) {
/>
)
return (
<CenteredView
style={[
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="blockedAccountsScreen">
<ViewHeader title={_(msg`Blocked Accounts`)} showOnDesktop />
<Text
type="sm"
<Layout.Screen testID="blockedAccountsScreen">
<CenteredView
style={[
styles.description,
pal.text,
isTabletOrDesktop && styles.descriptionDesktop,
]}>
<Trans>
Blocked accounts cannot reply in your threads, mention you, or
otherwise interact with you. You will not see their content and they
will be prevented from seeing yours.
</Trans>
</Text>
{isEmpty ? (
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
{isError ? (
<ErrorScreen
title="Oops!"
message={cleanError(error)}
onPressTryAgain={refetch}
/>
) : (
<View style={[styles.empty, pal.viewLight]}>
<Text type="lg" style={[pal.text, styles.emptyText]}>
<Trans>
You have not blocked any accounts yet. To block an account, go
to their profile and select "Block account" from the menu on
their account.
</Trans>
</Text>
</View>
)}
</View>
) : (
<FlatList
style={[!isTabletOrDesktop && styles.flex1]}
data={profiles}
keyExtractor={(item: ActorDefs.ProfileView) => item.did}
refreshControl={
<RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="blockedAccountsScreen">
<ViewHeader title={_(msg`Blocked Accounts`)} showOnDesktop />
<Text
type="sm"
style={[
styles.description,
pal.text,
isTabletOrDesktop && styles.descriptionDesktop,
]}>
<Trans>
Blocked accounts cannot reply in your threads, mention you, or
otherwise interact with you. You will not see their content and they
will be prevented from seeing yours.
</Trans>
</Text>
{isEmpty ? (
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
{isError ? (
<ErrorScreen
title="Oops!"
message={cleanError(error)}
onPressTryAgain={refetch}
/>
) : (
<View style={[styles.empty, pal.viewLight]}>
<Text type="lg" style={[pal.text, styles.emptyText]}>
<Trans>
You have not blocked any accounts yet. To block an account,
go to their profile and select "Block account" from the menu
on their account.
</Trans>
</Text>
</View>
)}
</View>
) : (
<FlatList
style={[!isTabletOrDesktop && styles.flex1]}
data={profiles}
keyExtractor={(item: ActorDefs.ProfileView) => item.did}
refreshControl={
<RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
ListFooterComponent={() => (
<View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View>
)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
)}
</CenteredView>
ListFooterComponent={() => (
<View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View>
)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
)}
</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 {SimpleViewHeader} from '#/view/com/util/SimpleViewHeader'
import {Text} from '#/view/com/util/text/Text'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ModerationModlists'>
export function ModerationModlistsScreen({}: Props) {
@@ -48,7 +49,7 @@ export function ModerationModlistsScreen({}: Props) {
}, [openModal, navigation])
return (
<View style={s.hContentRegion} testID="moderationModlistsScreen">
<Layout.Screen testID="moderationModlistsScreen">
<SimpleViewHeader
showBackButton={isMobile}
style={
@@ -82,6 +83,6 @@ export function ModerationModlistsScreen({}: Props) {
</View>
</SimpleViewHeader>
<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 {useSetMinimalShellMode} from '#/state/shell'
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 {ErrorScreen} from '../com/util/error/ErrorScreen'
import {Text} from '../com/util/text/Text'
import {ViewHeader} from '../com/util/ViewHeader'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -95,75 +96,77 @@ export function ModerationMutedAccounts({}: Props) {
/>
)
return (
<CenteredView
style={[
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="mutedAccountsScreen">
<ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop />
<Text
type="sm"
<Layout.Screen testID="mutedAccountsScreen">
<CenteredView
style={[
styles.description,
pal.text,
isTabletOrDesktop && styles.descriptionDesktop,
]}>
<Trans>
Muted accounts have their posts removed from your feed and from your
notifications. Mutes are completely private.
</Trans>
</Text>
{isEmpty ? (
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
{isError ? (
<ErrorScreen
title="Oops!"
message={cleanError(error)}
onPressTryAgain={refetch}
/>
) : (
<View style={[styles.empty, pal.viewLight]}>
<Text type="lg" style={[pal.text, styles.emptyText]}>
<Trans>
You have not muted any accounts yet. To mute an account, go to
their profile and select "Mute account" from the menu on their
account.
</Trans>
</Text>
</View>
)}
</View>
) : (
<FlatList
style={[!isTabletOrDesktop && styles.flex1]}
data={profiles}
keyExtractor={item => item.did}
refreshControl={
<RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
styles.container,
isTabletOrDesktop && styles.containerDesktop,
pal.view,
pal.border,
]}
testID="mutedAccountsScreen">
<ViewHeader title={_(msg`Muted Accounts`)} showOnDesktop />
<Text
type="sm"
style={[
styles.description,
pal.text,
isTabletOrDesktop && styles.descriptionDesktop,
]}>
<Trans>
Muted accounts have their posts removed from your feed and from your
notifications. Mutes are completely private.
</Trans>
</Text>
{isEmpty ? (
<View style={[pal.border, !isTabletOrDesktop && styles.flex1]}>
{isError ? (
<ErrorScreen
title="Oops!"
message={cleanError(error)}
onPressTryAgain={refetch}
/>
) : (
<View style={[styles.empty, pal.viewLight]}>
<Text type="lg" style={[pal.text, styles.emptyText]}>
<Trans>
You have not muted any accounts yet. To mute an account, go
to their profile and select "Mute account" from the menu on
their account.
</Trans>
</Text>
</View>
)}
</View>
) : (
<FlatList
style={[!isTabletOrDesktop && styles.flex1]}
data={profiles}
keyExtractor={item => item.did}
refreshControl={
<RefreshControl
refreshing={isPTRing}
onRefresh={onRefresh}
tintColor={pal.colors.text}
titleColor={pal.colors.text}
/>
}
onEndReached={onEndReached}
renderItem={renderItem}
initialNumToRender={15}
// FIXME(dan)
ListFooterComponent={() => (
<View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View>
)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
)}
</CenteredView>
ListFooterComponent={() => (
<View style={styles.footer}>
{(isFetching || isFetchingNextPage) && <ActivityIndicator />}
</View>
)}
// @ts-ignore our .web version only -prf
desktopFixedHeight
/>
)}
</CenteredView>
</Layout.Screen>
)
}
+13 -11
View File
@@ -1,19 +1,21 @@
import React from 'react'
import {StyleSheet, View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {
useNavigation,
StackActions,
useFocusEffect,
useNavigation,
} from '@react-navigation/native'
import {ViewHeader} from '../com/util/ViewHeader'
import {Text} from '../com/util/text/Text'
import {Button} from 'view/com/util/forms/Button'
import {NavigationProp} from 'lib/routes/types'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {usePalette} from '#/lib/hooks/usePalette'
import {NavigationProp} from '#/lib/routes/types'
import {s} from '#/lib/styles'
import {useSetMinimalShellMode} from '#/state/shell'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {Button} from '#/view/com/util/forms/Button'
import {Text} from '#/view/com/util/text/Text'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
export const NotFoundScreen = () => {
const pal = usePalette('default')
@@ -38,7 +40,7 @@ export const NotFoundScreen = () => {
}, [navigation, canGoBack])
return (
<View testID="notFoundView" style={pal.view}>
<Layout.Screen testID="notFoundView">
<ViewHeader title={_(msg`Page Not Found`)} />
<View style={styles.container}>
<Text type="title-2xl" style={[pal.text, s.mb10]}>
@@ -61,7 +63,7 @@ export const NotFoundScreen = () => {
onPress={onPressHome}
/>
</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 {Button} from '#/components/Button'
import {SettingsGear2_Stroke2_Corner0_Rounded as SettingsIcon} from '#/components/icons/SettingsGear2'
import * as Layout from '#/components/Layout'
import {Link} from '#/components/Link'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
@@ -192,39 +193,38 @@ export function NotificationsScreen({route: {params}}: Props) {
}, [renderButton, isLoadingLatest])
return (
<CenteredView
testID="notificationsScreen"
style={[s.hContentRegion, {paddingTop: 2}]}
sideBorders={true}>
<ViewHeader
title={_(msg`Notifications`)}
canGoBack={false}
showBorder={true}
renderButton={renderHeaderSpinner}
/>
<MainScrollProvider>
<Feed
onScrolledDownChange={setIsScrolledDown}
scrollElRef={scrollElRef}
ListHeaderComponent={ListHeaderComponent}
overridePriorityNotifications={params?.show === 'all'}
<Layout.Screen testID="notificationsScreen">
<CenteredView style={[a.flex_1, {paddingTop: 2}]} sideBorders={true}>
<ViewHeader
title={_(msg`Notifications`)}
canGoBack={false}
showBorder={true}
renderButton={renderHeaderSpinner}
/>
</MainScrollProvider>
{(isScrolledDown || hasNew) && (
<LoadLatestBtn
onPress={onPressLoadLatest}
label={_(msg`Load new notifications`)}
showIndicator={hasNew}
<MainScrollProvider>
<Feed
onScrolledDownChange={setIsScrolledDown}
scrollElRef={scrollElRef}
ListHeaderComponent={ListHeaderComponent}
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=""
/>
)}
<FAB
testID="composeFAB"
onPress={() => openComposer({})}
icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />}
accessibilityRole="button"
accessibilityLabel={_(msg`New post`)}
accessibilityHint=""
/>
</CenteredView>
</CenteredView>
</Layout.Screen>
)
}
+49 -46
View File
@@ -13,6 +13,7 @@ import {atoms as a, useTheme} from '#/alf'
import {Admonition} from '#/components/Admonition'
import {Error} from '#/components/Error'
import * as Toggle from '#/components/forms/Toggle'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
import {Text} from '#/components/Typography'
@@ -35,52 +36,54 @@ export function NotificationsSettingsScreen({}: Props) {
: serverPriority
return (
<ScrollView stickyHeaderIndices={[0]}>
<ViewHeader
title={_(msg`Notification Settings`)}
showOnDesktop
showBorder
/>
{isQueryError ? (
<Error
title={_(msg`Oops!`)}
message={_(msg`Something went wrong!`)}
onRetry={refetch}
sideBorders={false}
<Layout.Screen>
<ScrollView stickyHeaderIndices={[0]}>
<ViewHeader
title={_(msg`Notification Settings`)}
showOnDesktop
showBorder
/>
) : (
<View style={[a.p_lg, a.gap_md]}>
<Text style={[a.text_lg, a.font_bold]}>
<FontAwesomeIcon icon="flask" style={t.atoms.text} />{' '}
<Trans>Notification filters</Trans>
</Text>
<Toggle.Group
label={_(msg`Priority notifications`)}
type="checkbox"
values={priority ? ['enabled'] : []}
onChange={onChangePriority}
disabled={typeof priority !== 'boolean' || isMutationPending}>
<View>
<Toggle.Item
name="enabled"
label={_(msg`Enable priority notifications`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Enable priority notifications</Trans>
</Toggle.LabelText>
{!data ? <Loader size="md" /> : <Toggle.Platform />}
</Toggle.Item>
</View>
</Toggle.Group>
<Admonition type="warning" style={[a.mt_sm]}>
<Trans>
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>
{isQueryError ? (
<Error
title={_(msg`Oops!`)}
message={_(msg`Something went wrong!`)}
onRetry={refetch}
sideBorders={false}
/>
) : (
<View style={[a.p_lg, a.gap_md]}>
<Text style={[a.text_lg, a.font_bold]}>
<FontAwesomeIcon icon="flask" style={t.atoms.text} />{' '}
<Trans>Notification filters</Trans>
</Text>
<Toggle.Group
label={_(msg`Priority notifications`)}
type="checkbox"
values={priority ? ['enabled'] : []}
onChange={onChangePriority}
disabled={typeof priority !== 'boolean' || isMutationPending}>
<View>
<Toggle.Item
name="enabled"
label={_(msg`Enable priority notifications`)}
style={[a.justify_between, a.py_sm]}>
<Toggle.LabelText>
<Trans>Enable priority notifications</Trans>
</Toggle.LabelText>
{!data ? <Loader size="md" /> : <Toggle.Platform />}
</Toggle.Item>
</View>
</Toggle.Group>
<Admonition type="warning" style={[a.mt_sm]}>
<Trans>
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 {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 {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {makeRecordUri} from 'lib/strings/url-helpers'
import {s} from 'lib/styles'
import {PostThread as PostThreadComponent} from '../com/post-thread/PostThread'
import {PostThread as PostThreadComponent} from '#/view/com/post-thread/PostThread'
import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PostThread'>
export function PostThreadScreen({route}: Props) {
@@ -22,10 +23,10 @@ export function PostThreadScreen({route}: Props) {
)
return (
<View style={s.hContentRegion}>
<View style={s.flex1}>
<Layout.Screen testID="postThreadScreen">
<View style={a.flex_1}>
<PostThreadComponent uri={uri} />
</View>
</View>
</Layout.Screen>
)
}
@@ -10,17 +10,17 @@ import {
EmbedPlayerSource,
externalEmbedLabels,
} from '#/lib/strings/embed-player'
import {s} from '#/lib/styles'
import {
useExternalEmbedsPrefs,
useSetExternalEmbedPref,
} from '#/state/preferences'
import {useSetMinimalShellMode} from '#/state/shell'
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 {SimpleViewHeader} from '../com/util/SimpleViewHeader'
import {Text} from '../com/util/text/Text'
import {ScrollView} from '../com/util/Views'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -38,7 +38,7 @@ export function PreferencesExternalEmbeds({}: Props) {
)
return (
<View style={s.hContentRegion} testID="preferencesExternalEmbedsScreen">
<Layout.Screen testID="preferencesExternalEmbedsScreen">
<ScrollView
// @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}}
@@ -81,7 +81,7 @@ export function PreferencesExternalEmbeds({}: Props) {
/>
))}
</ScrollView>
</View>
</Layout.Screen>
)
}
@@ -17,6 +17,7 @@ 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 * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<
CommonNavigatorParams,
@@ -35,7 +36,7 @@ export function PreferencesFollowingFeed({}: Props) {
)
return (
<View testID="preferencesHomeFeedScreen" style={s.hContentRegion}>
<Layout.Screen testID="preferencesHomeFeedScreen">
<ScrollView
// @ts-ignore web only -sfn
dataSet={{'stable-gutters': 1}}
@@ -185,7 +186,7 @@ export function PreferencesFollowingFeed({}: Props) {
</View>
</View>
</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 {ScrollView} from '#/view/com/util/Views'
import {atoms as a} from '#/alf'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'PreferencesThreads'>
export function PreferencesThreads({}: Props) {
@@ -38,7 +39,7 @@ export function PreferencesThreads({}: Props) {
)
return (
<View testID="preferencesThreadsScreen" style={s.hContentRegion}>
<Layout.Screen testID="preferencesThreadsScreen">
<ScrollView
// @ts-ignore web only -prf
dataSet={{'stable-gutters': 1}}
@@ -134,7 +135,7 @@ export function PreferencesThreads({}: Props) {
<ActivityIndicator style={a.flex_1} />
)}
</ScrollView>
</View>
</Layout.Screen>
)
}
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react'
import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
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 {msg, Trans} from '@lingui/macro'
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'>
export const PrivacyPolicyScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const PrivacyPolicyScreen = (_props: Props) => {
)
return (
<View>
<Layout.Screen>
<ViewHeader title={_(msg`Privacy Policy`)} />
<ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}>
@@ -42,6 +44,6 @@ export const PrivacyPolicyScreen = (_props: Props) => {
</View>
<View style={s.footerSpacer} />
</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 {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels'
import {web} from '#/alf'
import * as Layout from '#/components/Layout'
import {ScreenHider} from '#/components/moderation/ScreenHider'
import {ProfileStarterPacks} from '#/components/StarterPack/ProfileStarterPacks'
import {navigate} from '#/Navigation'
@@ -55,7 +56,15 @@ interface SectionRef {
}
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 {currentAccount} = useSession()
const queryClient = useQueryClient()
+30 -23
View File
@@ -61,6 +61,7 @@ import {
} from '#/components/icons/Heart2'
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import * as Layout from '#/components/Layout'
import {InlineLinkText} from '#/components/Link'
import * as Menu from '#/components/Menu'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
@@ -96,36 +97,42 @@ export function ProfileFeedScreen(props: Props) {
if (error) {
return (
<CenteredView>
<View style={[pal.view, pal.border, styles.notFoundContainer]}>
<Text type="title-lg" style={[pal.text, s.mb10]}>
<Trans>Could not load feed</Trans>
</Text>
<Text type="md" style={[pal.text, s.mb20]}>
{error.toString()}
</Text>
<Layout.Screen testID="profileFeedScreenError">
<CenteredView>
<View style={[pal.view, pal.border, styles.notFoundContainer]}>
<Text type="title-lg" style={[pal.text, s.mb10]}>
<Trans>Could not load feed</Trans>
</Text>
<Text type="md" style={[pal.text, s.mb20]}>
{error.toString()}
</Text>
<View style={{flexDirection: 'row'}}>
<Button
type="default"
accessibilityLabel={_(msg`Go back`)}
accessibilityHint={_(msg`Returns to previous page`)}
onPress={onPressBack}
style={{flexShrink: 1}}>
<Text type="button" style={pal.text}>
<Trans>Go Back</Trans>
</Text>
</Button>
<View style={{flexDirection: 'row'}}>
<Button
type="default"
accessibilityLabel={_(msg`Go back`)}
accessibilityHint={_(msg`Returns to previous page`)}
onPress={onPressBack}
style={{flexShrink: 1}}>
<Text type="button" style={pal.text}>
<Trans>Go Back</Trans>
</Text>
</Button>
</View>
</View>
</View>
</CenteredView>
</CenteredView>
</Layout.Screen>
)
}
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 {View} from 'react-native'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
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 {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {makeRecordUri} from 'lib/strings/url-helpers'
import {PostLikedBy as PostLikedByComponent} from '../com/post-thread/PostLikedBy'
import {ViewHeader} from '../com/util/ViewHeader'
import {PostLikedBy as PostLikedByComponent} from '#/view/com/post-thread/PostLikedBy'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import * as Layout from '#/components/Layout'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFeedLikedBy'>
export const ProfileFeedLikedByScreen = ({route}: Props) => {
@@ -24,9 +24,9 @@ export const ProfileFeedLikedByScreen = ({route}: Props) => {
)
return (
<View style={{flex: 1}}>
<Layout.Screen testID="postLikedByScreen">
<ViewHeader title={_(msg`Liked By`)} />
<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 {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {isWeb} from 'platform/detection'
import {CenteredView} from 'view/com/util/Views'
import {atoms as a} from '#/alf'
import {ProfileFollowers as ProfileFollowersComponent} from '#/view/com/profile/ProfileFollowers'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists'
import {ProfileFollowers as ProfileFollowersComponent} from '../com/profile/ProfileFollowers'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollowers'>
export const ProfileFollowersScreen = ({route}: Props) => {
@@ -25,10 +25,12 @@ export const ProfileFollowersScreen = ({route}: Props) => {
)
return (
<CenteredView style={a.util_screen_outer} sideBorders={true}>
<ListHeaderDesktop title={_(msg`Followers`)} />
<ViewHeader title={_(msg`Followers`)} showBorder={!isWeb} />
<ProfileFollowersComponent name={name} />
</CenteredView>
<Layout.Screen testID="profileFollowersScreen">
<CenteredView sideBorders={true}>
<ListHeaderDesktop title={_(msg`Followers`)} />
<ViewHeader title={_(msg`Followers`)} showBorder={!isWeb} />
<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 {useFocusEffect} from '@react-navigation/native'
import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
import {isWeb} from '#/platform/detection'
import {useSetMinimalShellMode} from '#/state/shell'
import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {isWeb} from 'platform/detection'
import {CenteredView} from 'view/com/util/Views'
import {atoms as a} from '#/alf'
import {ProfileFollows as ProfileFollowsComponent} from '#/view/com/profile/ProfileFollows'
import {ViewHeader} from '#/view/com/util/ViewHeader'
import {CenteredView} from '#/view/com/util/Views'
import * as Layout from '#/components/Layout'
import {ListHeaderDesktop} from '#/components/Lists'
import {ProfileFollows as ProfileFollowsComponent} from '../com/profile/ProfileFollows'
import {ViewHeader} from '../com/util/ViewHeader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileFollows'>
export const ProfileFollowsScreen = ({route}: Props) => {
@@ -25,10 +25,12 @@ export const ProfileFollowsScreen = ({route}: Props) => {
)
return (
<CenteredView style={a.util_screen_outer} sideBorders={true}>
<ListHeaderDesktop title={_(msg`Following`)} />
<ViewHeader title={_(msg`Following`)} showBorder={!isWeb} />
<ProfileFollowsComponent name={name} />
</CenteredView>
<Layout.Screen testID="profileFollowsScreen">
<CenteredView sideBorders={true}>
<ListHeaderDesktop title={_(msg`Following`)} />
<ViewHeader title={_(msg`Following`)} showBorder={!isWeb} />
<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 {atoms as a, useTheme} from '#/alf'
import {useDialogControl} from '#/components/Dialog'
import * as Layout from '#/components/Layout'
import * as Hider from '#/components/moderation/Hider'
import * as Prompt from '#/components/Prompt'
import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog'
@@ -87,6 +88,14 @@ interface SectionRef {
type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'>
export function ProfileListScreen(props: Props) {
return (
<Layout.Screen testID="profileListScreen">
<ProfileListScreenInner {...props} />
</Layout.Screen>
)
}
function ProfileListScreenInner(props: Props) {
const {_} = useLingui()
const {name: handleOrDid, rkey} = props.route.params
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 {Button, ButtonIcon, ButtonText} from '#/components/Button'
import {FilterTimeline_Stroke2_Corner0_Rounded as FilterTimeline} from '#/components/icons/FilterTimeline'
import * as Layout from '#/components/Layout'
import {Loader} from '#/components/Loader'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'SavedFeeds'>
@@ -106,120 +107,117 @@ function SavedFeedsInner({
}, [_, isDesktop, onSaveChanges, hasUnsavedChanges, isOverwritePending])
return (
<CenteredView
style={[
s.hContentRegion,
pal.border,
isTabletOrDesktop && styles.desktopContainer,
]}>
<ViewHeader
title={_(msg`Edit My Feeds`)}
showOnDesktop
showBorder
renderButton={renderHeaderBtn}
/>
<ScrollView style={s.flex1} contentContainerStyle={[styles.noBorder]}>
{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>
<Layout.Screen>
<CenteredView
style={[a.util_screen_outer]}
sideBorders={isTabletOrDesktop}>
<ViewHeader
title={_(msg`Edit My Feeds`)}
showOnDesktop
showBorder
renderButton={renderHeaderBtn}
/>
<ScrollView style={[a.flex_1]} contentContainerStyle={[a.border_0]}>
{noSavedFeedsOfAnyType && (
<View style={[pal.border, a.border_b]}>
<NoSavedFeedsOfAnyType />
</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.border, {borderBottomWidth: StyleSheet.hairlineWidth}]}>
<NoFollowingFeed />
<View style={[pal.text, pal.border, styles.title]}>
<Text type="title" style={pal.text}>
<Trans>Pinned Feeds</Trans>
</Text>
</View>
)}
<View style={[pal.text, pal.border, styles.title]}>
<Text type="title" style={pal.text}>
<Trans>Saved Feeds</Trans>
</Text>
</View>
{preferences ? (
!unpinnedFeeds.length ? (
<View
style={[
pal.border,
isMobile && s.flex1,
pal.viewLight,
styles.empty,
]}>
<Text type="lg" style={[pal.text]}>
<Trans>You don't have any saved 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>
) : (
pinnedFeeds.map(f => (
<ListItem
key={f.id}
feed={f}
isPinned
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : (
unpinnedFeeds.map(f => (
<ListItem
key={f.id}
feed={f}
isPinned={false}
currentFeeds={currentFeeds}
setCurrentFeeds={setCurrentFeeds}
preferences={preferences}
/>
))
)
) : (
<ActivityIndicator style={{marginTop: 20}} />
)}
<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>
{noFollowingFeed && (
<View style={[pal.border, a.border_b]}>
<NoFollowingFeed />
</View>
)}
<View style={[pal.text, pal.border, styles.title]}>
<Text type="title" style={pal.text}>
<Trans>Saved Feeds</Trans>
</Text>
</View>
{preferences ? (
!unpinnedFeeds.length ? (
<View
style={[
pal.border,
isMobile && s.flex1,
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({
desktopContainer: {
borderLeftWidth: 1,
borderRightWidth: 1,
// @ts-ignore only rendered on web
minHeight: '100vh',
},
empty: {
paddingHorizontal: 20,
paddingVertical: 20,
@@ -463,10 +455,4 @@ const styles = StyleSheet.create({
paddingTop: 22,
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 {useLingui} from '@lingui/react'
import {cleanError} from '#/lib/strings/errors'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {useGetPopularFeedsQuery} from '#/state/queries/feed'
import {usePreferencesQuery} from '#/state/queries/preferences'
import {useSuggestedFollowsQuery} from '#/state/queries/suggested-follows'
import {cleanError} from 'lib/strings/errors'
import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard'
import {List} from '#/view/com/util/List'
import {UserAvatar} from '#/view/com/util/UserAvatar'
import {
FeedFeedLoadingPlaceholder,
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 {Button} from '#/components/Button'
import * as FeedCard from '#/components/FeedCard'
@@ -564,6 +564,8 @@ export function Explore() {
[t, moderationOpts],
)
// note: actually not a screen, instead it's nested within
// the search screen. so we don't need Layout.Screen
return (
<List
data={items}
+3 -2
View File
@@ -65,6 +65,7 @@ import * as FeedCard from '#/components/FeedCard'
import {SearchInput} from '#/components/forms/SearchInput'
import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDown} from '#/components/icons/Chevron'
import {Menu_Stroke2_Corner0_Rounded as Menu} from '#/components/icons/Menu'
import * as Layout from '#/components/Layout'
function Loader() {
const pal = usePalette('default')
@@ -852,7 +853,7 @@ export function SearchScreen(
}, [setShowAutocomplete])
return (
<View style={isWeb ? null : {flex: 1}}>
<Layout.Screen testID="searchScreen">
<CenteredView
style={[
a.p_md,
@@ -957,7 +958,7 @@ export function SearchScreen(
headerHeight={headerHeight}
/>
</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 {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings'
import {VerifyEmailDialog} from '#/components/dialogs/VerifyEmailDialog'
import * as Layout from '#/components/Layout'
import {Email2FAToggle} from './Email2FAToggle'
import {ExportCarDialog} from './ExportCarDialog'
@@ -286,7 +287,7 @@ export function SettingsScreen({}: Props) {
const {mutate: onPressDeleteChatDeclaration} = useDeleteActorDeclaration()
return (
<View style={s.hContentRegion} testID="settingsScreen">
<Layout.Screen testID="settingsScreen">
<ExportCarDialog control={exportCarControl} />
<BirthDateSettingsDialog control={birthdayControl} />
@@ -919,7 +920,7 @@ export function SettingsScreen({}: Props) {
</View>
<View style={s.footerSpacer} />
</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 {atoms as a, ThemeProvider, useTheme} from '#/alf'
import {Button, ButtonText} from '#/components/Button'
import * as Layout from '#/components/Layout'
import {Admonitions} from './Admonitions'
import {Breakpoints} from './Breakpoints'
import {Buttons} from './Buttons'
@@ -21,12 +22,16 @@ import {Theming} from './Theming'
import {Typography} from './Typography'
export function Storybook() {
if (isWeb) return <StorybookInner />
return (
<ScrollView>
<StorybookInner />
</ScrollView>
<Layout.Screen>
{isWeb ? (
<StorybookInner />
) : (
<ScrollView>
<StorybookInner />
</ScrollView>
)}
</Layout.Screen>
)
}
+15 -14
View File
@@ -1,17 +1,18 @@
import React from 'react'
import {View} from 'react-native'
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 {msg, Trans} from '@lingui/macro'
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'>
export const SupportScreen = (_props: Props) => {
@@ -26,7 +27,7 @@ export const SupportScreen = (_props: Props) => {
)
return (
<View>
<Layout.Screen>
<ViewHeader title={_(msg`Support`)} />
<CenteredView>
<Text type="title-xl" style={[pal.text, s.p20, s.pb5]}>
@@ -44,6 +45,6 @@ export const SupportScreen = (_props: Props) => {
</Trans>
</Text>
</CenteredView>
</View>
</Layout.Screen>
)
}
+14 -12
View File
@@ -1,16 +1,18 @@
import React from 'react'
import {View} from 'react-native'
import {useFocusEffect} from '@react-navigation/native'
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 {msg, Trans} from '@lingui/macro'
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'>
export const TermsOfServiceScreen = (_props: Props) => {
@@ -25,7 +27,7 @@ export const TermsOfServiceScreen = (_props: Props) => {
)
return (
<View>
<Layout.Screen>
<ViewHeader title={_(msg`Terms of Service`)} />
<ScrollView style={[s.hContentRegion, pal.view]}>
<View style={[s.p20]}>
@@ -40,6 +42,6 @@ export const TermsOfServiceScreen = (_props: Props) => {
</View>
<View style={s.footerSpacer} />
</ScrollView>
</View>
</Layout.Screen>
)
}
+9 -19
View File
@@ -1,14 +1,7 @@
import React from 'react'
import {
BackHandler,
DimensionValue,
StyleSheet,
useWindowDimensions,
View,
} from 'react-native'
import {BackHandler, StyleSheet, useWindowDimensions, View} from 'react-native'
import {Drawer} from 'react-native-drawer-layout'
import Animated from 'react-native-reanimated'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import * as NavigationBar from 'expo-navigation-bar'
import {StatusBar} from 'expo-status-bar'
import {useNavigation, useNavigationState} from '@react-navigation/native'
@@ -32,6 +25,7 @@ import {useCloseAnyActiveElement} 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 {SigninDialog} from '#/components/dialogs/Signin'
import {Outlet as PortalOutlet} from '#/components/Portal'
@@ -46,11 +40,7 @@ function ShellInner() {
const isDrawerSwipeDisabled = useIsDrawerSwipeDisabled()
const setIsDrawerOpen = useSetDrawerOpen()
const winDim = useWindowDimensions()
const safeAreaInsets = useSafeAreaInsets()
const containerPadding = React.useMemo(
() => ({height: '100%' as DimensionValue, paddingTop: safeAreaInsets.top}),
[safeAreaInsets],
)
const renderDrawerContent = React.useCallback(() => <DrawerContent />, [])
const onOpenDrawer = React.useCallback(
() => setIsDrawerOpen(true),
@@ -68,14 +58,14 @@ function ShellInner() {
useNotificationsHandler()
React.useEffect(() => {
let listener = {remove() {}}
if (isAndroid) {
listener = BackHandler.addEventListener('hardwareBackPress', () => {
const listener = BackHandler.addEventListener('hardwareBackPress', () => {
return closeAnyActiveElement()
})
}
return () => {
listener.remove()
return () => {
listener.remove()
}
}
}, [closeAnyActiveElement])
@@ -102,7 +92,7 @@ function ShellInner() {
return (
<>
<Animated.View style={containerPadding}>
<Animated.View style={[a.h_full]}>
<ErrorBoundary>
<Drawer
renderDrawerContent={renderDrawerContent}
+8 -7
View File
@@ -7,19 +7,20 @@ import {useNavigation} from '@react-navigation/native'
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
import {useIntentHandler} from '#/lib/hooks/useIntentHandler'
import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {NavigationProp} from '#/lib/routes/types'
import {colors, s} from '#/lib/styles'
import {colors} from '#/lib/styles'
import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell'
import {useComposerKeyboardShortcut} from '#/state/shell/composer/useComposerKeyboardShortcut'
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 {SigninDialog} from '#/components/dialogs/Signin'
import {Outlet as PortalOutlet} from '#/components/Portal'
import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries'
import {FlatNavigator, RoutesContainer} from '../../Navigation'
import {Lightbox} from '../com/lightbox/Lightbox'
import {ModalsContainer} from '../com/modals/Modal'
import {ErrorBoundary} from '../com/util/ErrorBoundary'
import {FlatNavigator, RoutesContainer} from '#/Navigation'
import {Composer} from './Composer.web'
import {DrawerContent} from './Drawer'
@@ -78,7 +79,7 @@ function ShellInner() {
export const Shell: React.FC = function ShellImpl() {
const pageBg = useColorSchemeStyle(styles.bgLight, styles.bgDark)
return (
<View style={[s.hContentRegion, pageBg]}>
<View style={[a.util_screen_outer, pageBg]}>
<RoutesContainer>
<ShellInner />
</RoutesContainer>