Merge branch 'main' into hailey/onboarding-profile
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ module.exports = function () {
|
||||
* iOS build number. Must be incremented for each TestFlight version.
|
||||
* WARNING: Always leave this variable on line 24! If it is moved, you need to update ./scripts/bumpIosBuildNumber.sh
|
||||
*/
|
||||
const IOS_BUILD_NUMBER = '5'
|
||||
const IOS_BUILD_NUMBER = '7'
|
||||
|
||||
/**
|
||||
* Android build number. Must be incremented for each release.
|
||||
|
||||
@@ -13,6 +13,7 @@ module.exports = {
|
||||
'uk',
|
||||
'ca',
|
||||
'zh-CN',
|
||||
'it',
|
||||
],
|
||||
catalogs: [
|
||||
{
|
||||
|
||||
@@ -30,8 +30,8 @@ export function IconCircle({
|
||||
a.align_center,
|
||||
a.rounded_full,
|
||||
{
|
||||
width: 64,
|
||||
height: 64,
|
||||
width: size === 'lg' ? 52 : 64,
|
||||
height: size === 'lg' ? 52 : 64,
|
||||
backgroundColor:
|
||||
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
|
||||
},
|
||||
@@ -140,6 +140,8 @@ export function sanitizeAppLanguageSetting(appLanguage: string): AppLanguage {
|
||||
return AppLanguage.ca
|
||||
case 'zh-CN':
|
||||
return AppLanguage.zh_CN
|
||||
case 'it':
|
||||
return AppLanguage.it
|
||||
default:
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {messages as messagesPt_BR} from '#/locale/locales/pt-BR/messages'
|
||||
import {messages as messagesUk} from '#/locale/locales/uk/messages'
|
||||
import {messages as messagesCa} from '#/locale/locales/ca/messages'
|
||||
import {messages as messagesZh_CN} from '#/locale/locales/zh-CN/messages'
|
||||
import {messages as messagesIt} from '#/locale/locales/it/messages'
|
||||
|
||||
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
|
||||
import {AppLanguage} from '#/locale/languages'
|
||||
@@ -65,6 +66,11 @@ export async function dynamicActivate(locale: AppLanguage) {
|
||||
}
|
||||
case AppLanguage.zh_CN: {
|
||||
i18n.loadAndActivate({locale, messages: messagesZh_CN})
|
||||
break
|
||||
}
|
||||
case AppLanguage.it: {
|
||||
i18n.loadAndActivate({locale, messages: messagesIt})
|
||||
break
|
||||
}
|
||||
default: {
|
||||
i18n.loadAndActivate({locale, messages: messagesEn})
|
||||
|
||||
@@ -56,6 +56,10 @@ export async function dynamicActivate(locale: AppLanguage) {
|
||||
mod = await import(`./locales/zh-CN/messages`)
|
||||
break
|
||||
}
|
||||
case AppLanguage.it: {
|
||||
mod = await import(`./locales/it/messages`)
|
||||
break
|
||||
}
|
||||
default: {
|
||||
mod = await import(`./locales/en/messages`)
|
||||
break
|
||||
|
||||
@@ -17,6 +17,7 @@ export enum AppLanguage {
|
||||
uk = 'uk',
|
||||
ca = 'ca',
|
||||
zh_CN = 'zh-CN',
|
||||
it = 'it',
|
||||
}
|
||||
|
||||
interface AppLanguageConfig {
|
||||
@@ -37,6 +38,7 @@ export const APP_LANGUAGES: AppLanguageConfig[] = [
|
||||
{code2: AppLanguage.uk, name: 'Українська – Ukrainian'},
|
||||
{code2: AppLanguage.ca, name: 'Català – Catalan'},
|
||||
{code2: AppLanguage.zh_CN, name: '简体中文(中国) – Chinese (Simplified)'},
|
||||
{code2: AppLanguage.it, name: 'Italiano - Italian'},
|
||||
]
|
||||
|
||||
export const LANGUAGES: Language[] = [
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ import {
|
||||
flatten,
|
||||
TextStyleProp,
|
||||
} from '#/alf'
|
||||
import {H2, P, leading} from '#/components/Typography'
|
||||
import {P, leading, Text} from '#/components/Typography'
|
||||
import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
||||
import {Button, ButtonIcon} from '#/components/Button'
|
||||
import {ScrollView} from '#/view/com/util/Views'
|
||||
@@ -209,16 +209,18 @@ export function Title({
|
||||
style,
|
||||
}: React.PropsWithChildren<TextStyleProp>) {
|
||||
return (
|
||||
<H2
|
||||
<Text
|
||||
style={[
|
||||
a.pb_sm,
|
||||
a.text_4xl,
|
||||
a.font_bold,
|
||||
{
|
||||
lineHeight: leading(a.text_4xl, a.leading_tight),
|
||||
},
|
||||
flatten(style),
|
||||
]}>
|
||||
{children}
|
||||
</H2>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
OnboardingControls,
|
||||
} from '#/screens/Onboarding/Layout'
|
||||
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
export type FeedConfig = {
|
||||
default: boolean
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
Description,
|
||||
OnboardingControls,
|
||||
} from '#/screens/Onboarding/Layout'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
import {
|
||||
bulkWriteFollows,
|
||||
sortPrimaryAlgorithmFeeds,
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
usePreferencesQuery,
|
||||
useSetFeedViewPreferencesMutation,
|
||||
} from 'state/queries/preferences'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
export function StepFollowingFeed() {
|
||||
const {_} = useLingui()
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
OnboardingControls,
|
||||
} from '#/screens/Onboarding/Layout'
|
||||
import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
export function StepInterests() {
|
||||
const {_} = useLingui()
|
||||
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
import {ModerationOption} from '#/screens/Onboarding/StepModeration/ModerationOption'
|
||||
import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/AdultContentEnabledPref'
|
||||
import {Context} from '#/screens/Onboarding/state'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
function AnimatedDivider() {
|
||||
return (
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
SuggestedAccountCardPlaceholder,
|
||||
} from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard'
|
||||
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
export function Inner({
|
||||
profiles,
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
} from '#/screens/Onboarding/Layout'
|
||||
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
||||
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
|
||||
export function StepTopicalFeeds() {
|
||||
const {_} = useLingui()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from 'react'
|
||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||
import {s, colors} from 'lib/styles'
|
||||
@@ -9,6 +10,14 @@ import {Trans, msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
import {Logotype} from '#/view/icons/Logotype'
|
||||
import {
|
||||
FontAwesomeIcon,
|
||||
FontAwesomeIconStyle,
|
||||
} from '@fortawesome/react-native-fontawesome'
|
||||
import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
|
||||
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
|
||||
import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
|
||||
import {APP_LANGUAGES} from '#/locale/languages'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onPressSignin,
|
||||
@@ -20,6 +29,22 @@ export const SplashScreen = ({
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const setLangPrefs = useLanguagePrefsApi()
|
||||
const insets = useSafeAreaInsets()
|
||||
|
||||
const sanitizedLang = sanitizeAppLanguageSetting(langPrefs.appLanguage)
|
||||
|
||||
const onChangeAppLanguage = React.useCallback(
|
||||
(value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
|
||||
if (!value) return
|
||||
if (sanitizedLang !== value) {
|
||||
setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
|
||||
}
|
||||
},
|
||||
[sanitizedLang, setLangPrefs],
|
||||
)
|
||||
|
||||
return (
|
||||
<CenteredView style={[styles.container, pal.view]}>
|
||||
<ErrorBoundary>
|
||||
@@ -58,6 +83,51 @@ export const SplashScreen = ({
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<View style={styles.footer}>
|
||||
<View style={{position: 'relative'}}>
|
||||
<RNPickerSelect
|
||||
placeholder={{}}
|
||||
value={sanitizedLang}
|
||||
onValueChange={onChangeAppLanguage}
|
||||
items={APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
|
||||
label: l.name,
|
||||
value: l.code2,
|
||||
key: l.code2,
|
||||
}))}
|
||||
useNativeAndroidPickerStyle={false}
|
||||
style={{
|
||||
inputAndroid: {
|
||||
color: pal.textLight.color,
|
||||
fontSize: 16,
|
||||
paddingRight: 10 + 4,
|
||||
},
|
||||
inputIOS: {
|
||||
color: pal.text.color,
|
||||
fontSize: 16,
|
||||
paddingRight: 10 + 4,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
pointerEvents: 'none',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}>
|
||||
<FontAwesomeIcon
|
||||
icon="chevron-down"
|
||||
size={10}
|
||||
style={pal.textLight as FontAwesomeIconStyle}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{height: insets.bottom}} />
|
||||
</ErrorBoundary>
|
||||
</CenteredView>
|
||||
)
|
||||
@@ -73,7 +143,7 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
},
|
||||
btns: {
|
||||
paddingBottom: 40,
|
||||
paddingBottom: 0,
|
||||
},
|
||||
title: {
|
||||
textAlign: 'center',
|
||||
@@ -95,4 +165,11 @@ const styles = StyleSheet.create({
|
||||
textAlign: 'center',
|
||||
fontSize: 21,
|
||||
},
|
||||
footer: {
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 12,
|
||||
paddingBottom: 24,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
})
|
||||
|
||||
@@ -9,9 +9,13 @@ import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {CenteredView} from '../util/Views'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {Trans, msg} from '@lingui/macro'
|
||||
import {Logo} from '#/view/icons/Logo'
|
||||
import {Logotype} from '#/view/icons/Logotype'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {sanitizeAppLanguageSetting} from '#/locale/helpers'
|
||||
import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
|
||||
import {APP_LANGUAGES} from '#/locale/languages'
|
||||
|
||||
export const SplashScreen = ({
|
||||
onDismiss,
|
||||
@@ -98,24 +102,84 @@ export const SplashScreen = ({
|
||||
|
||||
function Footer({styles}: {styles: ReturnType<typeof useStyles>}) {
|
||||
const pal = usePalette('default')
|
||||
const {_} = useLingui()
|
||||
|
||||
const langPrefs = useLanguagePrefs()
|
||||
const setLangPrefs = useLanguagePrefsApi()
|
||||
|
||||
const sanitizedLang = sanitizeAppLanguageSetting(langPrefs.appLanguage)
|
||||
|
||||
const onChangeAppLanguage = React.useCallback(
|
||||
(ev: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const value = ev.target.value
|
||||
|
||||
if (!value) return
|
||||
if (sanitizedLang !== value) {
|
||||
setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
|
||||
}
|
||||
},
|
||||
[sanitizedLang, setLangPrefs],
|
||||
)
|
||||
|
||||
return (
|
||||
<View style={[styles.footer, pal.view, pal.border]}>
|
||||
<TextLink
|
||||
href="https://bsky.social"
|
||||
text="Business"
|
||||
text={_(msg`Business`)}
|
||||
style={[styles.footerLink, pal.link]}
|
||||
/>
|
||||
<TextLink
|
||||
href="https://bsky.social/about/blog"
|
||||
text="Blog"
|
||||
text={_(msg`Blog`)}
|
||||
style={[styles.footerLink, pal.link]}
|
||||
/>
|
||||
<TextLink
|
||||
href="https://bsky.social/about/join"
|
||||
text="Jobs"
|
||||
text={_(msg`Jobs`)}
|
||||
style={[styles.footerLink, pal.link]}
|
||||
/>
|
||||
|
||||
<View style={styles.footerDivider} />
|
||||
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
gap: 8,
|
||||
alignItems: 'center',
|
||||
flexShrink: 1,
|
||||
}}>
|
||||
<Text aria-hidden={true} style={[pal.textLight]}>
|
||||
{APP_LANGUAGES.find(l => l.code2 === sanitizedLang)?.name}
|
||||
</Text>
|
||||
<FontAwesomeIcon
|
||||
icon="chevron-down"
|
||||
size={12}
|
||||
style={[pal.textLight, {flexShrink: 0}]}
|
||||
/>
|
||||
|
||||
<select
|
||||
value={sanitizedLang}
|
||||
onChange={onChangeAppLanguage}
|
||||
style={{
|
||||
cursor: 'pointer',
|
||||
MozAppearance: 'none',
|
||||
WebkitAppearance: 'none',
|
||||
appearance: 'none',
|
||||
position: 'absolute',
|
||||
inset: 0,
|
||||
width: '100%',
|
||||
color: 'transparent',
|
||||
background: 'transparent',
|
||||
border: 0,
|
||||
padding: 0,
|
||||
}}>
|
||||
{APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => (
|
||||
<option key={l.code2} value={l.code2}>
|
||||
{l.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
@@ -188,9 +252,10 @@ const useStyles = () => {
|
||||
padding: 20,
|
||||
borderTopWidth: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 20,
|
||||
},
|
||||
footerLink: {
|
||||
marginRight: 20,
|
||||
},
|
||||
footerDivider: {flexGrow: 1},
|
||||
footerLink: {},
|
||||
})
|
||||
}
|
||||
|
||||
+127
-88
@@ -16,6 +16,7 @@ import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
|
||||
import {s} from 'lib/styles'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
|
||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||
import {
|
||||
@@ -41,8 +42,11 @@ import {
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useSession} from '#/state/session'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {isNative, isWeb} from '#/platform/detection'
|
||||
import {HITSLOP_10} from 'lib/constants'
|
||||
import {IconCircle} from '#/components/IconCircle'
|
||||
import {ListSparkle_Stroke2_Corner0_Rounded} from '#/components/icons/ListSparkle'
|
||||
import {ListMagnifyingGlass_Stroke2_Corner0_Rounded} from '#/components/icons/ListMagnifyingGlass'
|
||||
|
||||
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
|
||||
|
||||
@@ -215,12 +219,7 @@ export function FeedsScreen(_props: Props) {
|
||||
// pendingItems: this.rootStore.preferences.savedFeeds.length || 3,
|
||||
})
|
||||
} else {
|
||||
if (preferences?.feeds?.saved.length === 0) {
|
||||
slices.push({
|
||||
key: 'savedFeedNoResults',
|
||||
type: 'savedFeedNoResults',
|
||||
})
|
||||
} else {
|
||||
if (preferences?.feeds?.saved.length !== 0) {
|
||||
const {saved, pinned} = preferences.feeds
|
||||
|
||||
slices = slices.concat(
|
||||
@@ -400,46 +399,48 @@ export function FeedsScreen(_props: Props) {
|
||||
) {
|
||||
return (
|
||||
<View style={s.p10}>
|
||||
<ActivityIndicator />
|
||||
<ActivityIndicator size="large" />
|
||||
</View>
|
||||
)
|
||||
} else if (item.type === 'savedFeedsHeader') {
|
||||
if (!isMobile) {
|
||||
return (
|
||||
<View
|
||||
style={[
|
||||
pal.view,
|
||||
styles.header,
|
||||
pal.border,
|
||||
{
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
]}>
|
||||
<Text type="title-lg" style={[pal.text, s.bold]}>
|
||||
<Trans>My Feeds</Trans>
|
||||
</Text>
|
||||
<View style={styles.headerBtnGroup}>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
hitSlop={HITSLOP_10}
|
||||
onPress={searchInputRef.current?.focus}>
|
||||
<MagnifyingGlassIcon2
|
||||
size={22}
|
||||
strokeWidth={2}
|
||||
style={pal.icon}
|
||||
/>
|
||||
</Pressable>
|
||||
<Link
|
||||
href="/settings/saved-feeds"
|
||||
accessibilityLabel={_(msg`Edit My Feeds`)}
|
||||
accessibilityHint="">
|
||||
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
||||
</Link>
|
||||
return (
|
||||
<>
|
||||
{!isMobile && (
|
||||
<View
|
||||
style={[
|
||||
pal.view,
|
||||
styles.header,
|
||||
pal.border,
|
||||
{
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
]}>
|
||||
<Text type="title-lg" style={[pal.text, s.bold]}>
|
||||
<Trans>Feeds</Trans>
|
||||
</Text>
|
||||
<View style={styles.headerBtnGroup}>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
hitSlop={HITSLOP_10}
|
||||
onPress={searchInputRef.current?.focus}>
|
||||
<MagnifyingGlassIcon2
|
||||
size={22}
|
||||
strokeWidth={2}
|
||||
style={pal.icon}
|
||||
/>
|
||||
</Pressable>
|
||||
<Link
|
||||
href="/settings/saved-feeds"
|
||||
accessibilityLabel={_(msg`Edit My Feeds`)}
|
||||
accessibilityHint="">
|
||||
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
||||
</Link>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
return <View />
|
||||
)}
|
||||
{preferences?.feeds?.saved?.length !== 0 && <FeedsSavedHeader />}
|
||||
</>
|
||||
)
|
||||
} else if (item.type === 'savedFeedNoResults') {
|
||||
return (
|
||||
<View
|
||||
@@ -457,47 +458,17 @@ export function FeedsScreen(_props: Props) {
|
||||
} else if (item.type === 'popularFeedsHeader') {
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
style={[
|
||||
pal.view,
|
||||
styles.header,
|
||||
{
|
||||
// This is first in the flatlist without a session -esb
|
||||
marginTop: hasSession ? 16 : 0,
|
||||
paddingLeft: isMobile ? 12 : undefined,
|
||||
paddingRight: 10,
|
||||
paddingBottom: isMobile ? 6 : undefined,
|
||||
},
|
||||
]}>
|
||||
<Text type="title-lg" style={[pal.text, s.bold]}>
|
||||
<Trans>Discover new feeds</Trans>
|
||||
</Text>
|
||||
|
||||
{!isMobile && (
|
||||
<SearchInput
|
||||
ref={searchInputRef}
|
||||
query={query}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onPressCancelSearch={onPressCancelSearch}
|
||||
onSubmitQuery={onSubmitQuery}
|
||||
setIsInputFocused={onChangeSearchFocus}
|
||||
style={{flex: 1, maxWidth: 250}}
|
||||
/>
|
||||
)}
|
||||
<FeedsAboutHeader />
|
||||
<View style={{paddingHorizontal: 12, paddingBottom: 12}}>
|
||||
<SearchInput
|
||||
ref={searchInputRef}
|
||||
query={query}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onPressCancelSearch={onPressCancelSearch}
|
||||
onSubmitQuery={onSubmitQuery}
|
||||
setIsInputFocused={onChangeSearchFocus}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{isMobile && (
|
||||
<View style={{paddingHorizontal: 8, paddingBottom: 10}}>
|
||||
<SearchInput
|
||||
ref={searchInputRef}
|
||||
query={query}
|
||||
onChangeQuery={onChangeQuery}
|
||||
onPressCancelSearch={onPressCancelSearch}
|
||||
onSubmitQuery={onSubmitQuery}
|
||||
setIsInputFocused={onChangeSearchFocus}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
} else if (item.type === 'popularFeedsLoading') {
|
||||
@@ -529,15 +500,20 @@ export function FeedsScreen(_props: Props) {
|
||||
return null
|
||||
},
|
||||
[
|
||||
_,
|
||||
hasSession,
|
||||
isMobile,
|
||||
pal,
|
||||
pal.view,
|
||||
pal.border,
|
||||
pal.text,
|
||||
pal.icon,
|
||||
pal.textLight,
|
||||
_,
|
||||
preferences?.feeds?.saved?.length,
|
||||
query,
|
||||
onChangeQuery,
|
||||
onPressCancelSearch,
|
||||
onSubmitQuery,
|
||||
onChangeSearchFocus,
|
||||
hasSession,
|
||||
],
|
||||
)
|
||||
|
||||
@@ -552,8 +528,6 @@ export function FeedsScreen(_props: Props) {
|
||||
/>
|
||||
)}
|
||||
|
||||
{preferences ? <View /> : <ActivityIndicator />}
|
||||
|
||||
<List
|
||||
ref={listRef}
|
||||
style={[!isTabletOrDesktop && s.flex1, styles.list]}
|
||||
@@ -660,6 +634,71 @@ function SavedFeedLoadingPlaceholder() {
|
||||
)
|
||||
}
|
||||
|
||||
function FeedsSavedHeader() {
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<View
|
||||
style={
|
||||
isWeb
|
||||
? [
|
||||
a.flex_row,
|
||||
a.px_md,
|
||||
a.py_lg,
|
||||
a.gap_md,
|
||||
a.border_b,
|
||||
t.atoms.border_contrast_low,
|
||||
]
|
||||
: [
|
||||
{flexDirection: 'row-reverse'},
|
||||
a.p_lg,
|
||||
a.gap_md,
|
||||
a.border_b,
|
||||
t.atoms.border_contrast_low,
|
||||
]
|
||||
}>
|
||||
<IconCircle icon={ListSparkle_Stroke2_Corner0_Rounded} size="lg" />
|
||||
<View style={[a.flex_1, a.gap_xs]}>
|
||||
<Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}>
|
||||
<Trans>My Feeds</Trans>
|
||||
</Text>
|
||||
<Text style={[t.atoms.text_contrast_high]}>
|
||||
<Trans>All the feeds you've saved, right in one place.</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
function FeedsAboutHeader() {
|
||||
const t = useTheme()
|
||||
|
||||
return (
|
||||
<View
|
||||
style={
|
||||
isWeb
|
||||
? [a.flex_row, a.px_md, a.pt_lg, a.pb_lg, a.gap_md]
|
||||
: [{flexDirection: 'row-reverse'}, a.p_lg, a.gap_md]
|
||||
}>
|
||||
<IconCircle
|
||||
icon={ListMagnifyingGlass_Stroke2_Corner0_Rounded}
|
||||
size="lg"
|
||||
/>
|
||||
<View style={[a.flex_1, a.gap_sm]}>
|
||||
<Text style={[a.flex_1, a.text_2xl, a.font_bold, t.atoms.text]}>
|
||||
<Trans>Discover New Feeds</Trans>
|
||||
</Text>
|
||||
<Text style={[t.atoms.text_contrast_high]}>
|
||||
<Trans>
|
||||
Custom feeds built by the community bring you new experiences and
|
||||
help you find the content you love.
|
||||
</Trans>
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
|
||||
Reference in New Issue
Block a user