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.
|
* 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
|
* 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.
|
* Android build number. Must be incremented for each release.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ module.exports = {
|
|||||||
'uk',
|
'uk',
|
||||||
'ca',
|
'ca',
|
||||||
'zh-CN',
|
'zh-CN',
|
||||||
|
'it',
|
||||||
],
|
],
|
||||||
catalogs: [
|
catalogs: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export function IconCircle({
|
|||||||
a.align_center,
|
a.align_center,
|
||||||
a.rounded_full,
|
a.rounded_full,
|
||||||
{
|
{
|
||||||
width: 64,
|
width: size === 'lg' ? 52 : 64,
|
||||||
height: 64,
|
height: size === 'lg' ? 52 : 64,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
|
t.name === 'light' ? t.palette.primary_50 : t.palette.primary_950,
|
||||||
},
|
},
|
||||||
@@ -140,6 +140,8 @@ export function sanitizeAppLanguageSetting(appLanguage: string): AppLanguage {
|
|||||||
return AppLanguage.ca
|
return AppLanguage.ca
|
||||||
case 'zh-CN':
|
case 'zh-CN':
|
||||||
return AppLanguage.zh_CN
|
return AppLanguage.zh_CN
|
||||||
|
case 'it':
|
||||||
|
return AppLanguage.it
|
||||||
default:
|
default:
|
||||||
continue
|
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 messagesUk} from '#/locale/locales/uk/messages'
|
||||||
import {messages as messagesCa} from '#/locale/locales/ca/messages'
|
import {messages as messagesCa} from '#/locale/locales/ca/messages'
|
||||||
import {messages as messagesZh_CN} from '#/locale/locales/zh-CN/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 {sanitizeAppLanguageSetting} from '#/locale/helpers'
|
||||||
import {AppLanguage} from '#/locale/languages'
|
import {AppLanguage} from '#/locale/languages'
|
||||||
@@ -65,6 +66,11 @@ export async function dynamicActivate(locale: AppLanguage) {
|
|||||||
}
|
}
|
||||||
case AppLanguage.zh_CN: {
|
case AppLanguage.zh_CN: {
|
||||||
i18n.loadAndActivate({locale, messages: messagesZh_CN})
|
i18n.loadAndActivate({locale, messages: messagesZh_CN})
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case AppLanguage.it: {
|
||||||
|
i18n.loadAndActivate({locale, messages: messagesIt})
|
||||||
|
break
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
i18n.loadAndActivate({locale, messages: messagesEn})
|
i18n.loadAndActivate({locale, messages: messagesEn})
|
||||||
|
|||||||
@@ -56,6 +56,10 @@ export async function dynamicActivate(locale: AppLanguage) {
|
|||||||
mod = await import(`./locales/zh-CN/messages`)
|
mod = await import(`./locales/zh-CN/messages`)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
case AppLanguage.it: {
|
||||||
|
mod = await import(`./locales/it/messages`)
|
||||||
|
break
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
mod = await import(`./locales/en/messages`)
|
mod = await import(`./locales/en/messages`)
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export enum AppLanguage {
|
|||||||
uk = 'uk',
|
uk = 'uk',
|
||||||
ca = 'ca',
|
ca = 'ca',
|
||||||
zh_CN = 'zh-CN',
|
zh_CN = 'zh-CN',
|
||||||
|
it = 'it',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppLanguageConfig {
|
interface AppLanguageConfig {
|
||||||
@@ -37,6 +38,7 @@ export const APP_LANGUAGES: AppLanguageConfig[] = [
|
|||||||
{code2: AppLanguage.uk, name: 'Українська – Ukrainian'},
|
{code2: AppLanguage.uk, name: 'Українська – Ukrainian'},
|
||||||
{code2: AppLanguage.ca, name: 'Català – Catalan'},
|
{code2: AppLanguage.ca, name: 'Català – Catalan'},
|
||||||
{code2: AppLanguage.zh_CN, name: '简体中文(中国) – Chinese (Simplified)'},
|
{code2: AppLanguage.zh_CN, name: '简体中文(中国) – Chinese (Simplified)'},
|
||||||
|
{code2: AppLanguage.it, name: 'Italiano - Italian'},
|
||||||
]
|
]
|
||||||
|
|
||||||
export const LANGUAGES: Language[] = [
|
export const LANGUAGES: Language[] = [
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -17,7 +17,7 @@ import {
|
|||||||
flatten,
|
flatten,
|
||||||
TextStyleProp,
|
TextStyleProp,
|
||||||
} from '#/alf'
|
} 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 {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron'
|
||||||
import {Button, ButtonIcon} from '#/components/Button'
|
import {Button, ButtonIcon} from '#/components/Button'
|
||||||
import {ScrollView} from '#/view/com/util/Views'
|
import {ScrollView} from '#/view/com/util/Views'
|
||||||
@@ -209,16 +209,18 @@ export function Title({
|
|||||||
style,
|
style,
|
||||||
}: React.PropsWithChildren<TextStyleProp>) {
|
}: React.PropsWithChildren<TextStyleProp>) {
|
||||||
return (
|
return (
|
||||||
<H2
|
<Text
|
||||||
style={[
|
style={[
|
||||||
a.pb_sm,
|
a.pb_sm,
|
||||||
|
a.text_4xl,
|
||||||
|
a.font_bold,
|
||||||
{
|
{
|
||||||
lineHeight: leading(a.text_4xl, a.leading_tight),
|
lineHeight: leading(a.text_4xl, a.leading_tight),
|
||||||
},
|
},
|
||||||
flatten(style),
|
flatten(style),
|
||||||
]}>
|
]}>
|
||||||
{children}
|
{children}
|
||||||
</H2>
|
</Text>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import {
|
|||||||
OnboardingControls,
|
OnboardingControls,
|
||||||
} from '#/screens/Onboarding/Layout'
|
} from '#/screens/Onboarding/Layout'
|
||||||
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
export type FeedConfig = {
|
export type FeedConfig = {
|
||||||
default: boolean
|
default: boolean
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import {
|
|||||||
Description,
|
Description,
|
||||||
OnboardingControls,
|
OnboardingControls,
|
||||||
} from '#/screens/Onboarding/Layout'
|
} from '#/screens/Onboarding/Layout'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
import {
|
import {
|
||||||
bulkWriteFollows,
|
bulkWriteFollows,
|
||||||
sortPrimaryAlgorithmFeeds,
|
sortPrimaryAlgorithmFeeds,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import {
|
|||||||
usePreferencesQuery,
|
usePreferencesQuery,
|
||||||
useSetFeedViewPreferencesMutation,
|
useSetFeedViewPreferencesMutation,
|
||||||
} from 'state/queries/preferences'
|
} from 'state/queries/preferences'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
export function StepFollowingFeed() {
|
export function StepFollowingFeed() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
OnboardingControls,
|
OnboardingControls,
|
||||||
} from '#/screens/Onboarding/Layout'
|
} from '#/screens/Onboarding/Layout'
|
||||||
import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton'
|
import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
export function StepInterests() {
|
export function StepInterests() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import {
|
|||||||
import {ModerationOption} from '#/screens/Onboarding/StepModeration/ModerationOption'
|
import {ModerationOption} from '#/screens/Onboarding/StepModeration/ModerationOption'
|
||||||
import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/AdultContentEnabledPref'
|
import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/AdultContentEnabledPref'
|
||||||
import {Context} from '#/screens/Onboarding/state'
|
import {Context} from '#/screens/Onboarding/state'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
function AnimatedDivider() {
|
function AnimatedDivider() {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
SuggestedAccountCardPlaceholder,
|
SuggestedAccountCardPlaceholder,
|
||||||
} from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard'
|
} from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard'
|
||||||
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
export function Inner({
|
export function Inner({
|
||||||
profiles,
|
profiles,
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import {
|
|||||||
} from '#/screens/Onboarding/Layout'
|
} from '#/screens/Onboarding/Layout'
|
||||||
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
|
||||||
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
import {aggregateInterestItems} from '#/screens/Onboarding/util'
|
||||||
import {IconCircle} from '#/screens/Onboarding/IconCircle'
|
import {IconCircle} from '#/components/IconCircle'
|
||||||
|
|
||||||
export function StepTopicalFeeds() {
|
export function StepTopicalFeeds() {
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
import {StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||||
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {Text} from 'view/com/util/text/Text'
|
import {Text} from 'view/com/util/text/Text'
|
||||||
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
import {ErrorBoundary} from 'view/com/util/ErrorBoundary'
|
||||||
import {s, colors} from 'lib/styles'
|
import {s, colors} from 'lib/styles'
|
||||||
@@ -9,6 +10,14 @@ import {Trans, msg} from '@lingui/macro'
|
|||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {Logo} from '#/view/icons/Logo'
|
import {Logo} from '#/view/icons/Logo'
|
||||||
import {Logotype} from '#/view/icons/Logotype'
|
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 = ({
|
export const SplashScreen = ({
|
||||||
onPressSignin,
|
onPressSignin,
|
||||||
@@ -20,6 +29,22 @@ export const SplashScreen = ({
|
|||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {_} = useLingui()
|
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 (
|
return (
|
||||||
<CenteredView style={[styles.container, pal.view]}>
|
<CenteredView style={[styles.container, pal.view]}>
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
@@ -58,6 +83,51 @@ export const SplashScreen = ({
|
|||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</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>
|
</ErrorBoundary>
|
||||||
</CenteredView>
|
</CenteredView>
|
||||||
)
|
)
|
||||||
@@ -73,7 +143,7 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
btns: {
|
btns: {
|
||||||
paddingBottom: 40,
|
paddingBottom: 0,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
@@ -95,4 +165,11 @@ const styles = StyleSheet.create({
|
|||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
fontSize: 21,
|
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 {CenteredView} from '../util/Views'
|
||||||
import {isWeb} from 'platform/detection'
|
import {isWeb} from 'platform/detection'
|
||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {Trans} from '@lingui/macro'
|
import {Trans, msg} from '@lingui/macro'
|
||||||
import {Logo} from '#/view/icons/Logo'
|
import {Logo} from '#/view/icons/Logo'
|
||||||
import {Logotype} from '#/view/icons/Logotype'
|
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 = ({
|
export const SplashScreen = ({
|
||||||
onDismiss,
|
onDismiss,
|
||||||
@@ -98,24 +102,84 @@ export const SplashScreen = ({
|
|||||||
|
|
||||||
function Footer({styles}: {styles: ReturnType<typeof useStyles>}) {
|
function Footer({styles}: {styles: ReturnType<typeof useStyles>}) {
|
||||||
const pal = usePalette('default')
|
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 (
|
return (
|
||||||
<View style={[styles.footer, pal.view, pal.border]}>
|
<View style={[styles.footer, pal.view, pal.border]}>
|
||||||
<TextLink
|
<TextLink
|
||||||
href="https://bsky.social"
|
href="https://bsky.social"
|
||||||
text="Business"
|
text={_(msg`Business`)}
|
||||||
style={[styles.footerLink, pal.link]}
|
style={[styles.footerLink, pal.link]}
|
||||||
/>
|
/>
|
||||||
<TextLink
|
<TextLink
|
||||||
href="https://bsky.social/about/blog"
|
href="https://bsky.social/about/blog"
|
||||||
text="Blog"
|
text={_(msg`Blog`)}
|
||||||
style={[styles.footerLink, pal.link]}
|
style={[styles.footerLink, pal.link]}
|
||||||
/>
|
/>
|
||||||
<TextLink
|
<TextLink
|
||||||
href="https://bsky.social/about/join"
|
href="https://bsky.social/about/join"
|
||||||
text="Jobs"
|
text={_(msg`Jobs`)}
|
||||||
style={[styles.footerLink, pal.link]}
|
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>
|
</View>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -188,9 +252,10 @@ const useStyles = () => {
|
|||||||
padding: 20,
|
padding: 20,
|
||||||
borderTopWidth: 1,
|
borderTopWidth: 1,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 20,
|
||||||
},
|
},
|
||||||
footerLink: {
|
footerDivider: {flexGrow: 1},
|
||||||
marginRight: 20,
|
footerLink: {},
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+127
-88
@@ -16,6 +16,7 @@ import {usePalette} from 'lib/hooks/usePalette'
|
|||||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
|
import {ComposeIcon2, CogIcon, MagnifyingGlassIcon2} from 'lib/icons'
|
||||||
import {s} from 'lib/styles'
|
import {s} from 'lib/styles'
|
||||||
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
|
import {SearchInput, SearchInputRef} from 'view/com/util/forms/SearchInput'
|
||||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||||
import {
|
import {
|
||||||
@@ -41,8 +42,11 @@ import {
|
|||||||
import {cleanError} from 'lib/strings/errors'
|
import {cleanError} from 'lib/strings/errors'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {useSession} from '#/state/session'
|
import {useSession} from '#/state/session'
|
||||||
import {isNative} from '#/platform/detection'
|
import {isNative, isWeb} from '#/platform/detection'
|
||||||
import {HITSLOP_10} from 'lib/constants'
|
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'>
|
type Props = NativeStackScreenProps<FeedsTabNavigatorParams, 'Feeds'>
|
||||||
|
|
||||||
@@ -215,12 +219,7 @@ export function FeedsScreen(_props: Props) {
|
|||||||
// pendingItems: this.rootStore.preferences.savedFeeds.length || 3,
|
// pendingItems: this.rootStore.preferences.savedFeeds.length || 3,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (preferences?.feeds?.saved.length === 0) {
|
if (preferences?.feeds?.saved.length !== 0) {
|
||||||
slices.push({
|
|
||||||
key: 'savedFeedNoResults',
|
|
||||||
type: 'savedFeedNoResults',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
const {saved, pinned} = preferences.feeds
|
const {saved, pinned} = preferences.feeds
|
||||||
|
|
||||||
slices = slices.concat(
|
slices = slices.concat(
|
||||||
@@ -400,46 +399,48 @@ export function FeedsScreen(_props: Props) {
|
|||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<View style={s.p10}>
|
<View style={s.p10}>
|
||||||
<ActivityIndicator />
|
<ActivityIndicator size="large" />
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
} else if (item.type === 'savedFeedsHeader') {
|
} else if (item.type === 'savedFeedsHeader') {
|
||||||
if (!isMobile) {
|
return (
|
||||||
return (
|
<>
|
||||||
<View
|
{!isMobile && (
|
||||||
style={[
|
<View
|
||||||
pal.view,
|
style={[
|
||||||
styles.header,
|
pal.view,
|
||||||
pal.border,
|
styles.header,
|
||||||
{
|
pal.border,
|
||||||
borderBottomWidth: 1,
|
{
|
||||||
},
|
borderBottomWidth: 1,
|
||||||
]}>
|
},
|
||||||
<Text type="title-lg" style={[pal.text, s.bold]}>
|
]}>
|
||||||
<Trans>My Feeds</Trans>
|
<Text type="title-lg" style={[pal.text, s.bold]}>
|
||||||
</Text>
|
<Trans>Feeds</Trans>
|
||||||
<View style={styles.headerBtnGroup}>
|
</Text>
|
||||||
<Pressable
|
<View style={styles.headerBtnGroup}>
|
||||||
accessibilityRole="button"
|
<Pressable
|
||||||
hitSlop={HITSLOP_10}
|
accessibilityRole="button"
|
||||||
onPress={searchInputRef.current?.focus}>
|
hitSlop={HITSLOP_10}
|
||||||
<MagnifyingGlassIcon2
|
onPress={searchInputRef.current?.focus}>
|
||||||
size={22}
|
<MagnifyingGlassIcon2
|
||||||
strokeWidth={2}
|
size={22}
|
||||||
style={pal.icon}
|
strokeWidth={2}
|
||||||
/>
|
style={pal.icon}
|
||||||
</Pressable>
|
/>
|
||||||
<Link
|
</Pressable>
|
||||||
href="/settings/saved-feeds"
|
<Link
|
||||||
accessibilityLabel={_(msg`Edit My Feeds`)}
|
href="/settings/saved-feeds"
|
||||||
accessibilityHint="">
|
accessibilityLabel={_(msg`Edit My Feeds`)}
|
||||||
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
accessibilityHint="">
|
||||||
</Link>
|
<CogIcon strokeWidth={1.5} style={pal.icon} size={28} />
|
||||||
|
</Link>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
)}
|
||||||
)
|
{preferences?.feeds?.saved?.length !== 0 && <FeedsSavedHeader />}
|
||||||
}
|
</>
|
||||||
return <View />
|
)
|
||||||
} else if (item.type === 'savedFeedNoResults') {
|
} else if (item.type === 'savedFeedNoResults') {
|
||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
@@ -457,47 +458,17 @@ export function FeedsScreen(_props: Props) {
|
|||||||
} else if (item.type === 'popularFeedsHeader') {
|
} else if (item.type === 'popularFeedsHeader') {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<View
|
<FeedsAboutHeader />
|
||||||
style={[
|
<View style={{paddingHorizontal: 12, paddingBottom: 12}}>
|
||||||
pal.view,
|
<SearchInput
|
||||||
styles.header,
|
ref={searchInputRef}
|
||||||
{
|
query={query}
|
||||||
// This is first in the flatlist without a session -esb
|
onChangeQuery={onChangeQuery}
|
||||||
marginTop: hasSession ? 16 : 0,
|
onPressCancelSearch={onPressCancelSearch}
|
||||||
paddingLeft: isMobile ? 12 : undefined,
|
onSubmitQuery={onSubmitQuery}
|
||||||
paddingRight: 10,
|
setIsInputFocused={onChangeSearchFocus}
|
||||||
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}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</View>
|
</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') {
|
} else if (item.type === 'popularFeedsLoading') {
|
||||||
@@ -529,15 +500,20 @@ export function FeedsScreen(_props: Props) {
|
|||||||
return null
|
return null
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
_,
|
|
||||||
hasSession,
|
|
||||||
isMobile,
|
isMobile,
|
||||||
pal,
|
pal.view,
|
||||||
|
pal.border,
|
||||||
|
pal.text,
|
||||||
|
pal.icon,
|
||||||
|
pal.textLight,
|
||||||
|
_,
|
||||||
|
preferences?.feeds?.saved?.length,
|
||||||
query,
|
query,
|
||||||
onChangeQuery,
|
onChangeQuery,
|
||||||
onPressCancelSearch,
|
onPressCancelSearch,
|
||||||
onSubmitQuery,
|
onSubmitQuery,
|
||||||
onChangeSearchFocus,
|
onChangeSearchFocus,
|
||||||
|
hasSession,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -552,8 +528,6 @@ export function FeedsScreen(_props: Props) {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{preferences ? <View /> : <ActivityIndicator />}
|
|
||||||
|
|
||||||
<List
|
<List
|
||||||
ref={listRef}
|
ref={listRef}
|
||||||
style={[!isTabletOrDesktop && s.flex1, styles.list]}
|
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({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
Reference in New Issue
Block a user