fix
This commit is contained in:
147
ios/patching/001-social-app-ios-config.patch
Normal file
147
ios/patching/001-social-app-ios-config.patch
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
diff --git a/app.config.js b/app.config.js
|
||||||
|
index 246d8abd3..349aefb3d 100644
|
||||||
|
--- a/app.config.js
|
||||||
|
+++ b/app.config.js
|
||||||
|
@@ -18,10 +18,7 @@ module.exports = function (_config) {
|
||||||
|
const IS_DEV = !IS_TESTFLIGHT || !IS_PRODUCTION
|
||||||
|
|
||||||
|
const ASSOCIATED_DOMAINS = [
|
||||||
|
- 'applinks:bsky.app',
|
||||||
|
- 'applinks:staging.bsky.app',
|
||||||
|
- 'appclips:bsky.app',
|
||||||
|
- 'appclips:go.bsky.app', // Allows App Clip to work when scanning QR codes
|
||||||
|
+ 'applinks:syu.is',
|
||||||
|
// When testing local services, enter an ngrok (et al) domain here. It must use a standard HTTP/HTTPS port.
|
||||||
|
...(IS_DEV || IS_TESTFLIGHT ? [] : []),
|
||||||
|
]
|
||||||
|
@@ -33,27 +30,24 @@ module.exports = function (_config) {
|
||||||
|
return {
|
||||||
|
expo: {
|
||||||
|
version: VERSION,
|
||||||
|
- name: 'Bluesky',
|
||||||
|
- slug: 'bluesky',
|
||||||
|
- scheme: 'bluesky',
|
||||||
|
+ name: 'Aiat',
|
||||||
|
+ slug: 'aiat',
|
||||||
|
+ scheme: 'syui',
|
||||||
|
owner: 'blueskysocial',
|
||||||
|
runtimeVersion: {
|
||||||
|
policy: 'appVersion',
|
||||||
|
},
|
||||||
|
- icon: './assets/app-icons/ios_icon_default_next.png',
|
||||||
|
+ icon: './assets/icon.png',
|
||||||
|
userInterfaceStyle: 'automatic',
|
||||||
|
primaryColor: '#1083fe',
|
||||||
|
newArchEnabled: false,
|
||||||
|
ios: {
|
||||||
|
supportsTablet: false,
|
||||||
|
- bundleIdentifier: 'xyz.blueskyweb.app',
|
||||||
|
+ bundleIdentifier: 'ai.syui.at',
|
||||||
|
config: {
|
||||||
|
usesNonExemptEncryption: false,
|
||||||
|
},
|
||||||
|
- icon:
|
||||||
|
- PLATFORM === 'web' // web build doesn't like .icon files
|
||||||
|
- ? './assets/app-icons/ios_icon_default_next.png'
|
||||||
|
- : './assets/app-icons/ios_icon_default.icon',
|
||||||
|
+ icon: './assets/icon.png',
|
||||||
|
infoPlist: {
|
||||||
|
UIBackgroundModes: ['remote-notification'],
|
||||||
|
NSCameraUsageDescription:
|
||||||
|
@@ -113,7 +107,7 @@ module.exports = function (_config) {
|
||||||
|
entitlements: {
|
||||||
|
'com.apple.developer.kernel.increased-memory-limit': true,
|
||||||
|
'com.apple.developer.kernel.extended-virtual-addressing': true,
|
||||||
|
- 'com.apple.security.application-groups': 'group.app.bsky',
|
||||||
|
+ 'com.apple.security.application-groups': 'group.ai.syui.at',
|
||||||
|
},
|
||||||
|
privacyManifests: {
|
||||||
|
NSPrivacyCollectedDataTypes: [
|
||||||
|
@@ -175,14 +169,14 @@ module.exports = function (_config) {
|
||||||
|
barStyle: 'light-content',
|
||||||
|
},
|
||||||
|
android: {
|
||||||
|
- icon: './assets/app-icons/android_icon_default_next.png',
|
||||||
|
+ icon: './assets/icon.png',
|
||||||
|
adaptiveIcon: {
|
||||||
|
foregroundImage: './assets/icon-android-foreground.png',
|
||||||
|
monochromeImage: './assets/icon-android-monochrome.png',
|
||||||
|
backgroundColor: '#006AFF',
|
||||||
|
},
|
||||||
|
googleServicesFile: './google-services.json',
|
||||||
|
- package: 'xyz.blueskyweb.app',
|
||||||
|
+ package: 'ai.syui.at',
|
||||||
|
intentFilters: [
|
||||||
|
{
|
||||||
|
action: 'VIEW',
|
||||||
|
@@ -190,7 +184,7 @@ module.exports = function (_config) {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
scheme: 'https',
|
||||||
|
- host: 'bsky.app',
|
||||||
|
+ host: 'syu.is',
|
||||||
|
},
|
||||||
|
IS_DEV && {
|
||||||
|
scheme: 'http',
|
||||||
|
@@ -213,9 +207,9 @@ module.exports = function (_config) {
|
||||||
|
: undefined,
|
||||||
|
codeSigningMetadata: UPDATES_ENABLED
|
||||||
|
? {
|
||||||
|
- keyid: 'main',
|
||||||
|
- alg: 'rsa-v1_5-sha256',
|
||||||
|
- }
|
||||||
|
+ keyid: 'main',
|
||||||
|
+ alg: 'rsa-v1_5-sha256',
|
||||||
|
+ }
|
||||||
|
: undefined,
|
||||||
|
checkAutomatically: 'NEVER',
|
||||||
|
},
|
||||||
|
@@ -225,7 +219,7 @@ module.exports = function (_config) {
|
||||||
|
'expo-web-browser',
|
||||||
|
[
|
||||||
|
'react-native-edge-to-edge',
|
||||||
|
- {android: {enforceNavigationBarContrast: false}},
|
||||||
|
+ { android: { enforceNavigationBarContrast: false } },
|
||||||
|
],
|
||||||
|
USE_SENTRY && [
|
||||||
|
'@sentry/react-native/expo',
|
||||||
|
@@ -386,7 +380,7 @@ module.exports = function (_config) {
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
- ['expo-screen-orientation', {initialOrientation: 'PORTRAIT_UP'}],
|
||||||
|
+ ['expo-screen-orientation', { initialOrientation: 'PORTRAIT_UP' }],
|
||||||
|
['expo-location'],
|
||||||
|
].filter(Boolean),
|
||||||
|
extra: {
|
||||||
|
@@ -397,26 +391,22 @@ module.exports = function (_config) {
|
||||||
|
appExtensions: [
|
||||||
|
{
|
||||||
|
targetName: 'Share-with-Bluesky',
|
||||||
|
- bundleIdentifier: 'xyz.blueskyweb.app.Share-with-Bluesky',
|
||||||
|
+ bundleIdentifier: 'ai.syui.at.Share-with-Bluesky',
|
||||||
|
entitlements: {
|
||||||
|
'com.apple.security.application-groups': [
|
||||||
|
- 'group.app.bsky',
|
||||||
|
+ 'group.ai.syui.at',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
targetName: 'BlueskyNSE',
|
||||||
|
- bundleIdentifier: 'xyz.blueskyweb.app.BlueskyNSE',
|
||||||
|
+ bundleIdentifier: 'ai.syui.at.BlueskyNSE',
|
||||||
|
entitlements: {
|
||||||
|
'com.apple.security.application-groups': [
|
||||||
|
- 'group.app.bsky',
|
||||||
|
+ 'group.ai.syui.at',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
- {
|
||||||
|
- targetName: 'BlueskyClip',
|
||||||
|
- bundleIdentifier: 'xyz.blueskyweb.app.AppClip',
|
||||||
|
- },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
diff --git a/src/view/screens/PrivacyPolicy.tsx b/src/view/screens/PrivacyPolicy.tsx
|
diff --git a/src/view/screens/PrivacyPolicy.tsx b/src/view/screens/PrivacyPolicy.tsx
|
||||||
index a89eaadc4..19f5b4107 100644
|
index a89eaadc4..1da393f03 100644
|
||||||
--- a/src/view/screens/PrivacyPolicy.tsx
|
--- a/src/view/screens/PrivacyPolicy.tsx
|
||||||
+++ b/src/view/screens/PrivacyPolicy.tsx
|
+++ b/src/view/screens/PrivacyPolicy.tsx
|
||||||
@@ -1,52 +1,13 @@
|
@@ -1,52 +1,13 @@
|
||||||
@@ -34,7 +34,7 @@ index a89eaadc4..19f5b4107 100644
|
|||||||
- setMinimalShellMode(false)
|
- setMinimalShellMode(false)
|
||||||
- }, [setMinimalShellMode]),
|
- }, [setMinimalShellMode]),
|
||||||
- )
|
- )
|
||||||
+import { useSetTitle } from '#/lib/hooks/useSetTitle'
|
+import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||||
|
|
||||||
+export function PrivacyPolicyScreen() {
|
+export function PrivacyPolicyScreen() {
|
||||||
+ useSetTitle('Privacy Policy')
|
+ useSetTitle('Privacy Policy')
|
||||||
@@ -61,7 +61,7 @@ index a89eaadc4..19f5b4107 100644
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
diff --git a/src/view/screens/TermsOfService.tsx b/src/view/screens/TermsOfService.tsx
|
diff --git a/src/view/screens/TermsOfService.tsx b/src/view/screens/TermsOfService.tsx
|
||||||
index d843c713c..b96f112fc 100644
|
index d843c713c..b81767bd5 100644
|
||||||
--- a/src/view/screens/TermsOfService.tsx
|
--- a/src/view/screens/TermsOfService.tsx
|
||||||
+++ b/src/view/screens/TermsOfService.tsx
|
+++ b/src/view/screens/TermsOfService.tsx
|
||||||
@@ -1,50 +1,13 @@
|
@@ -1,50 +1,13 @@
|
||||||
@@ -96,7 +96,7 @@ index d843c713c..b96f112fc 100644
|
|||||||
- setMinimalShellMode(false)
|
- setMinimalShellMode(false)
|
||||||
- }, [setMinimalShellMode]),
|
- }, [setMinimalShellMode]),
|
||||||
- )
|
- )
|
||||||
+import { useSetTitle } from '#/lib/hooks/useSetTitle'
|
+import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
||||||
|
|
||||||
+export function TermsOfServiceScreen() {
|
+export function TermsOfServiceScreen() {
|
||||||
+ useSetTitle('Terms of Service')
|
+ useSetTitle('Terms of Service')
|
||||||
|
|||||||
@@ -1,15 +1,27 @@
|
|||||||
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
|
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
|
||||||
index fa33a9d56..642076b96 100644
|
index fa33a9d56..a9b724c4e 100644
|
||||||
--- a/src/Navigation.tsx
|
--- a/src/Navigation.tsx
|
||||||
+++ b/src/Navigation.tsx
|
+++ b/src/Navigation.tsx
|
||||||
@@ -50,6 +50,7 @@ import {
|
@@ -67,6 +67,7 @@ import {ProfileFeedLikedByScreen} from '#/view/screens/ProfileFeedLikedBy'
|
||||||
snoozeEmailConfirmationPrompt,
|
import {Storybook} from '#/view/screens/Storybook'
|
||||||
} from '#/state/shell/reminders'
|
import {SupportScreen} from '#/view/screens/Support'
|
||||||
import {CommunityGuidelinesScreen} from '#/view/screens/CommunityGuidelines'
|
import {TermsOfServiceScreen} from '#/view/screens/TermsOfService'
|
||||||
+import {LicenseScreen} from '#/view/screens/License'
|
+import {LicenseScreen} from '#/view/screens/License'
|
||||||
import {CopyrightPolicyScreen} from '#/view/screens/CopyrightPolicy'
|
import {BottomBar} from '#/view/shell/bottom-bar/BottomBar'
|
||||||
import {DebugModScreen} from '#/view/screens/DebugMod'
|
import {createNativeStackNavigatorWithAuth} from '#/view/shell/createNativeStackNavigatorWithAuth'
|
||||||
import {FeedsScreen} from '#/view/screens/Feeds'
|
import {BookmarksScreen} from '#/screens/Bookmarks'
|
||||||
|
@@ -335,6 +336,11 @@ function commonScreens(Stack: typeof Flat, unreadCountLabel?: string) {
|
||||||
|
getComponent={() => TermsOfServiceScreen}
|
||||||
|
options={{title: title(msg`Terms of Service`)}}
|
||||||
|
/>
|
||||||
|
+ <Stack.Screen
|
||||||
|
+ name="License"
|
||||||
|
+ getComponent={() => LicenseScreen}
|
||||||
|
+ options={{title: title(msg`License`)}}
|
||||||
|
+ />
|
||||||
|
<Stack.Screen
|
||||||
|
name="CommunityGuidelines"
|
||||||
|
getComponent={() => CommunityGuidelinesScreen}
|
||||||
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
|
diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts
|
||||||
index c315a8341..9b2f50a83 100644
|
index c315a8341..9b2f50a83 100644
|
||||||
--- a/src/lib/routes/types.ts
|
--- a/src/lib/routes/types.ts
|
||||||
@@ -22,642 +34,15 @@ index c315a8341..9b2f50a83 100644
|
|||||||
CommunityGuidelines: undefined
|
CommunityGuidelines: undefined
|
||||||
CopyrightPolicy: undefined
|
CopyrightPolicy: undefined
|
||||||
LanguageSettings: undefined
|
LanguageSettings: undefined
|
||||||
diff --git a/src/routes.ts b/src/routes.ts
|
|
||||||
index 1ed913bb2..77ea6deca 100644
|
|
||||||
--- a/src/routes.ts
|
|
||||||
+++ b/src/routes.ts
|
|
||||||
@@ -71,8 +71,8 @@ export const router = new Router<AllNavigatableRoutes>({
|
|
||||||
MiscellaneousNotificationSettings: '/settings/notifications/miscellaneous',
|
|
||||||
// support
|
|
||||||
Support: '/support',
|
|
||||||
- PrivacyPolicy: '/support/privacy',
|
|
||||||
- TermsOfService: '/support/tos',
|
|
||||||
+ PrivacyPolicy: 'https://syu.is/about/support/privacy-policy',
|
|
||||||
+ TermsOfService: 'https://syu.is/about/support/tos',
|
|
||||||
CommunityGuidelines: '/support/community-guidelines',
|
|
||||||
CopyrightPolicy: '/support/copyright',
|
|
||||||
// hashtags
|
|
||||||
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
|
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
|
||||||
index ed2a6cfb7..982c40b55 100644
|
index ed2a6cfb7..0b429e6f3 100644
|
||||||
--- a/src/view/shell/Drawer.tsx
|
--- a/src/view/shell/Drawer.tsx
|
||||||
+++ b/src/view/shell/Drawer.tsx
|
+++ b/src/view/shell/Drawer.tsx
|
||||||
@@ -1,60 +1,50 @@
|
@@ -460,6 +460,11 @@ function ExtraLinks() {
|
||||||
-import React, {type ComponentProps, type JSX} from 'react'
|
<Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
-import {Linking, ScrollView, TouchableOpacity, View} from 'react-native'
|
<Trans>Privacy Policy</Trans>
|
||||||
-import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
|
||||||
-import {msg, Plural, plural, Trans} from '@lingui/macro'
|
|
||||||
-import {useLingui} from '@lingui/react'
|
|
||||||
-import {StackActions, useNavigation} from '@react-navigation/native'
|
|
||||||
-
|
|
||||||
-import {useActorStatus} from '#/lib/actor-status'
|
|
||||||
-import {FEEDBACK_FORM_URL, HELP_DESK_URL} from '#/lib/constants'
|
|
||||||
-import {type PressableScale} from '#/lib/custom-animations/PressableScale'
|
|
||||||
-import {useNavigationTabState} from '#/lib/hooks/useNavigationTabState'
|
|
||||||
-import {getTabState, TabState} from '#/lib/routes/helpers'
|
|
||||||
-import {type NavigationProp} from '#/lib/routes/types'
|
|
||||||
-import {sanitizeHandle} from '#/lib/strings/handles'
|
|
||||||
-import {colors} from '#/lib/styles'
|
|
||||||
-import {isWeb} from '#/platform/detection'
|
|
||||||
-import {emitSoftReset} from '#/state/events'
|
|
||||||
-import {useKawaiiMode} from '#/state/preferences/kawaii'
|
|
||||||
-import {useUnreadNotifications} from '#/state/queries/notifications/unread'
|
|
||||||
-import {useProfileQuery} from '#/state/queries/profile'
|
|
||||||
-import {type SessionAccount, useSession} from '#/state/session'
|
|
||||||
-import {useSetDrawerOpen} from '#/state/shell'
|
|
||||||
-import {formatCount} from '#/view/com/util/numeric/format'
|
|
||||||
-import {UserAvatar} from '#/view/com/util/UserAvatar'
|
|
||||||
-import {NavSignupCard} from '#/view/shell/NavSignupCard'
|
|
||||||
-import {atoms as a, tokens, useTheme, web} from '#/alf'
|
|
||||||
-import {Button, ButtonIcon, ButtonText} from '#/components/Button'
|
|
||||||
-import {Divider} from '#/components/Divider'
|
|
||||||
+import React, { type ComponentProps, type JSX } from 'react'
|
|
||||||
+import { Linking, ScrollView, TouchableOpacity, View } from 'react-native'
|
|
||||||
+import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
||||||
+import { msg, Plural, plural, Trans } from '@lingui/macro'
|
|
||||||
+import { useLingui } from '@lingui/react'
|
|
||||||
+import { StackActions, useNavigation } from '@react-navigation/native'
|
|
||||||
+
|
|
||||||
+import { useActorStatus } from '#/lib/actor-status'
|
|
||||||
+import { FEEDBACK_FORM_URL, HELP_DESK_URL } from '#/lib/constants'
|
|
||||||
+import { type PressableScale } from '#/lib/custom-animations/PressableScale'
|
|
||||||
+import { useNavigationTabState } from '#/lib/hooks/useNavigationTabState'
|
|
||||||
+import { getTabState, TabState } from '#/lib/routes/helpers'
|
|
||||||
+import { type NavigationProp } from '#/lib/routes/types'
|
|
||||||
+import { sanitizeHandle } from '#/lib/strings/handles'
|
|
||||||
+import { colors } from '#/lib/styles'
|
|
||||||
+import { isWeb } from '#/platform/detection'
|
|
||||||
+import { emitSoftReset } from '#/state/events'
|
|
||||||
+import { useKawaiiMode } from '#/state/preferences/kawaii'
|
|
||||||
+import { useUnreadNotifications } from '#/state/queries/notifications/unread'
|
|
||||||
+import { useProfileQuery } from '#/state/queries/profile'
|
|
||||||
+import { type SessionAccount, useSession } from '#/state/session'
|
|
||||||
+import { useSetDrawerOpen } from '#/state/shell'
|
|
||||||
+import { formatCount } from '#/view/com/util/numeric/format'
|
|
||||||
+import { UserAvatar } from '#/view/com/util/UserAvatar'
|
|
||||||
+import { NavSignupCard } from '#/view/shell/NavSignupCard'
|
|
||||||
+import { atoms as a, tokens, useTheme, web } from '#/alf'
|
|
||||||
+import { Button } from '#/components/Button'
|
|
||||||
+import { Divider } from '#/components/Divider'
|
|
||||||
import {
|
|
||||||
Bell_Filled_Corner0_Rounded as BellFilled,
|
|
||||||
Bell_Stroke2_Corner0_Rounded as Bell,
|
|
||||||
} from '#/components/icons/Bell'
|
|
||||||
-import {Bookmark, BookmarkFilled} from '#/components/icons/Bookmark'
|
|
||||||
-import {BulletList_Stroke2_Corner0_Rounded as List} from '#/components/icons/BulletList'
|
|
||||||
-import {
|
|
||||||
- Hashtag_Filled_Corner0_Rounded as HashtagFilled,
|
|
||||||
- Hashtag_Stroke2_Corner0_Rounded as Hashtag,
|
|
||||||
-} from '#/components/icons/Hashtag'
|
|
||||||
import {
|
|
||||||
HomeOpen_Filled_Corner0_Rounded as HomeFilled,
|
|
||||||
HomeOpen_Stoke2_Corner0_Rounded as Home,
|
|
||||||
} from '#/components/icons/HomeOpen'
|
|
||||||
-import {MagnifyingGlass_Filled_Stroke2_Corner0_Rounded as MagnifyingGlassFilled} from '#/components/icons/MagnifyingGlass'
|
|
||||||
-import {MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlass} from '#/components/icons/MagnifyingGlass2'
|
|
||||||
-import {
|
|
||||||
- Message_Stroke2_Corner0_Rounded as Message,
|
|
||||||
- Message_Stroke2_Corner0_Rounded_Filled as MessageFilled,
|
|
||||||
-} from '#/components/icons/Message'
|
|
||||||
-import {SettingsGear2_Stroke2_Corner0_Rounded as Settings} from '#/components/icons/SettingsGear2'
|
|
||||||
+import { MagnifyingGlass_Filled_Stroke2_Corner0_Rounded as MagnifyingGlassFilled } from '#/components/icons/MagnifyingGlass'
|
|
||||||
+import { MagnifyingGlass2_Stroke2_Corner0_Rounded as MagnifyingGlass } from '#/components/icons/MagnifyingGlass2'
|
|
||||||
+import { SettingsGear2_Stroke2_Corner0_Rounded as Settings } from '#/components/icons/SettingsGear2'
|
|
||||||
import {
|
|
||||||
UserCircle_Filled_Corner0_Rounded as UserCircleFilled,
|
|
||||||
UserCircle_Stroke2_Corner0_Rounded as UserCircle,
|
|
||||||
} from '#/components/icons/UserCircle'
|
|
||||||
-import {InlineLinkText} from '#/components/Link'
|
|
||||||
-import {Text} from '#/components/Typography'
|
|
||||||
-import {useSimpleVerificationState} from '#/components/verification'
|
|
||||||
-import {VerificationCheck} from '#/components/verification/VerificationCheck'
|
|
||||||
+import { InlineLinkText } from '#/components/Link'
|
|
||||||
+import { Text } from '#/components/Typography'
|
|
||||||
+import { useSimpleVerificationState } from '#/components/verification'
|
|
||||||
+import { VerificationCheck } from '#/components/verification/VerificationCheck'
|
|
||||||
|
|
||||||
const iconWidth = 26
|
|
||||||
|
|
||||||
@@ -65,11 +55,11 @@ let DrawerProfileCard = ({
|
|
||||||
account: SessionAccount
|
|
||||||
onPressProfile: () => void
|
|
||||||
}): React.ReactNode => {
|
|
||||||
- const {_, i18n} = useLingui()
|
|
||||||
+ const { _, i18n } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
- const {data: profile} = useProfileQuery({did: account.did})
|
|
||||||
- const verification = useSimpleVerificationState({profile})
|
|
||||||
- const {isActive: live} = useActorStatus(profile)
|
|
||||||
+ const { data: profile } = useProfileQuery({ did: account.did })
|
|
||||||
+ const verification = useSimpleVerificationState({ profile })
|
|
||||||
+ const { isActive: live } = useActorStatus(profile)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TouchableOpacity
|
|
||||||
@@ -81,7 +71,6 @@ let DrawerProfileCard = ({
|
|
||||||
<UserAvatar
|
|
||||||
size={52}
|
|
||||||
avatar={profile?.avatar}
|
|
||||||
- // See https://github.com/bluesky-social/social-app/pull/1801:
|
|
||||||
usePlainRNImage={true}
|
|
||||||
type={profile?.associated?.labeler ? 'labeler' : 'user'}
|
|
||||||
live={live}
|
|
||||||
@@ -140,9 +129,9 @@ let DrawerProfileCard = ({
|
|
||||||
)
|
|
||||||
}
|
|
||||||
DrawerProfileCard = React.memo(DrawerProfileCard)
|
|
||||||
-export {DrawerProfileCard}
|
|
||||||
+export { DrawerProfileCard }
|
|
||||||
|
|
||||||
-let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
+let DrawerContent = ({ }: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
const t = useTheme()
|
|
||||||
const insets = useSafeAreaInsets()
|
|
||||||
const setDrawerOpen = useSetDrawerOpen()
|
|
||||||
@@ -150,27 +139,20 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
const {
|
|
||||||
isAtHome,
|
|
||||||
isAtSearch,
|
|
||||||
- isAtFeeds,
|
|
||||||
- isAtBookmarks,
|
|
||||||
isAtNotifications,
|
|
||||||
isAtMyProfile,
|
|
||||||
- isAtMessages,
|
|
||||||
} = useNavigationTabState()
|
|
||||||
- const {hasSession, currentAccount} = useSession()
|
|
||||||
-
|
|
||||||
- // events
|
|
||||||
- // =
|
|
||||||
+ const { hasSession, currentAccount } = useSession()
|
|
||||||
|
|
||||||
const onPressTab = React.useCallback(
|
|
||||||
(tab: 'Home' | 'Search' | 'Messages' | 'Notifications' | 'MyProfile') => {
|
|
||||||
const state = navigation.getState()
|
|
||||||
setDrawerOpen(false)
|
|
||||||
if (isWeb) {
|
|
||||||
- // hack because we have flat navigator for web and MyProfile does not exist on the web navigator -ansh
|
|
||||||
if (tab === 'MyProfile') {
|
|
||||||
- navigation.navigate('Profile', {name: currentAccount!.handle})
|
|
||||||
+ navigation.navigate('Profile', { name: currentAccount!.handle })
|
|
||||||
} else {
|
|
||||||
- // @ts-expect-error struggles with string unions, apparently
|
|
||||||
+ // @ts-expect-error struggles with string unions
|
|
||||||
navigation.navigate(tab)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
@@ -178,21 +160,11 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
if (tabState === TabState.InsideAtRoot) {
|
|
||||||
emitSoftReset()
|
|
||||||
} else if (tabState === TabState.Inside) {
|
|
||||||
- // find the correct navigator in which to pop-to-top
|
|
||||||
- const target = state.routes.find(route => route.name === `${tab}Tab`)
|
|
||||||
- ?.state?.key
|
|
||||||
+ const target = state.routes.find(route => route.name === `${tab}Tab`)?.state?.key
|
|
||||||
if (target) {
|
|
||||||
- // if we found it, trigger pop-to-top
|
|
||||||
- navigation.dispatch({
|
|
||||||
- ...StackActions.popToTop(),
|
|
||||||
- target,
|
|
||||||
- })
|
|
||||||
+ navigation.dispatch({ ...StackActions.popToTop(), target })
|
|
||||||
} else {
|
|
||||||
- // fallback: reset navigation
|
|
||||||
- navigation.reset({
|
|
||||||
- index: 0,
|
|
||||||
- routes: [{name: `${tab}Tab`}],
|
|
||||||
- })
|
|
||||||
+ navigation.reset({ index: 0, routes: [{ name: `${tab}Tab` }] })
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
navigation.navigate(`${tab}Tab`)
|
|
||||||
@@ -203,76 +175,21 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
)
|
|
||||||
|
|
||||||
const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab])
|
|
||||||
-
|
|
||||||
- const onPressSearch = React.useCallback(
|
|
||||||
- () => onPressTab('Search'),
|
|
||||||
- [onPressTab],
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const onPressMessages = React.useCallback(
|
|
||||||
- () => onPressTab('Messages'),
|
|
||||||
- [onPressTab],
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const onPressNotifications = React.useCallback(
|
|
||||||
- () => onPressTab('Notifications'),
|
|
||||||
- [onPressTab],
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const onPressProfile = React.useCallback(() => {
|
|
||||||
- onPressTab('MyProfile')
|
|
||||||
- }, [onPressTab])
|
|
||||||
-
|
|
||||||
- const onPressMyFeeds = React.useCallback(() => {
|
|
||||||
- navigation.navigate('Feeds')
|
|
||||||
- setDrawerOpen(false)
|
|
||||||
- }, [navigation, setDrawerOpen])
|
|
||||||
-
|
|
||||||
- const onPressLists = React.useCallback(() => {
|
|
||||||
- navigation.navigate('Lists')
|
|
||||||
- setDrawerOpen(false)
|
|
||||||
- }, [navigation, setDrawerOpen])
|
|
||||||
-
|
|
||||||
- const onPressBookmarks = React.useCallback(() => {
|
|
||||||
- navigation.navigate('Bookmarks')
|
|
||||||
- setDrawerOpen(false)
|
|
||||||
- }, [navigation, setDrawerOpen])
|
|
||||||
-
|
|
||||||
+ const onPressSearch = React.useCallback(() => onPressTab('Search'), [onPressTab])
|
|
||||||
+ const onPressNotifications = React.useCallback(() => onPressTab('Notifications'), [onPressTab])
|
|
||||||
+ const onPressProfile = React.useCallback(() => { onPressTab('MyProfile') }, [onPressTab])
|
|
||||||
const onPressSettings = React.useCallback(() => {
|
|
||||||
navigation.navigate('Settings')
|
|
||||||
setDrawerOpen(false)
|
|
||||||
}, [navigation, setDrawerOpen])
|
|
||||||
|
|
||||||
- const onPressFeedback = React.useCallback(() => {
|
|
||||||
- Linking.openURL(
|
|
||||||
- FEEDBACK_FORM_URL({
|
|
||||||
- email: currentAccount?.email,
|
|
||||||
- handle: currentAccount?.handle,
|
|
||||||
- }),
|
|
||||||
- )
|
|
||||||
- }, [currentAccount])
|
|
||||||
-
|
|
||||||
- const onPressHelp = React.useCallback(() => {
|
|
||||||
- Linking.openURL(HELP_DESK_URL)
|
|
||||||
- }, [])
|
|
||||||
-
|
|
||||||
- // rendering
|
|
||||||
- // =
|
|
||||||
-
|
|
||||||
return (
|
|
||||||
<View
|
|
||||||
testID="drawer"
|
|
||||||
style={[a.flex_1, a.border_r, t.atoms.bg, t.atoms.border_contrast_low]}>
|
|
||||||
<ScrollView
|
|
||||||
style={[a.flex_1]}
|
|
||||||
- contentContainerStyle={[
|
|
||||||
- {
|
|
||||||
- paddingTop: Math.max(
|
|
||||||
- insets.top + a.pt_xl.paddingTop,
|
|
||||||
- a.pt_xl.paddingTop,
|
|
||||||
- ),
|
|
||||||
- },
|
|
||||||
- ]}>
|
|
||||||
+ contentContainerStyle={[{ paddingTop: Math.max(insets.top + a.pt_xl.paddingTop, a.pt_xl.paddingTop) }]}>
|
|
||||||
<View style={[a.px_xl]}>
|
|
||||||
{hasSession && currentAccount ? (
|
|
||||||
<DrawerProfileCard
|
|
||||||
@@ -284,7 +201,6 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
<NavSignupCard />
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
-
|
|
||||||
<Divider style={[a.mt_xl, a.mb_sm]} />
|
|
||||||
</View>
|
|
||||||
|
|
||||||
@@ -292,17 +208,10 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
<>
|
|
||||||
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
|
|
||||||
<HomeMenuItem isActive={isAtHome} onPress={onPressHome} />
|
|
||||||
- <ChatMenuItem isActive={isAtMessages} onPress={onPressMessages} />
|
|
||||||
<NotificationsMenuItem
|
|
||||||
isActive={isAtNotifications}
|
|
||||||
onPress={onPressNotifications}
|
|
||||||
/>
|
|
||||||
- <FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} />
|
|
||||||
- <ListsMenuItem onPress={onPressLists} />
|
|
||||||
- <BookmarksMenuItem
|
|
||||||
- isActive={isAtBookmarks}
|
|
||||||
- onPress={onPressBookmarks}
|
|
||||||
- />
|
|
||||||
<ProfileMenuItem
|
|
||||||
isActive={isAtMyProfile}
|
|
||||||
onPress={onPressProfile}
|
|
||||||
@@ -312,7 +221,6 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<HomeMenuItem isActive={isAtHome} onPress={onPressHome} />
|
|
||||||
- <FeedsMenuItem isActive={isAtFeeds} onPress={onPressMyFeeds} />
|
|
||||||
<SearchMenuItem isActive={isAtSearch} onPress={onPressSearch} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
@@ -322,69 +230,11 @@ let DrawerContent = ({}: React.PropsWithoutRef<{}>): React.ReactNode => {
|
|
||||||
<ExtraLinks />
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
-
|
|
||||||
- <DrawerFooter
|
|
||||||
- onPressFeedback={onPressFeedback}
|
|
||||||
- onPressHelp={onPressHelp}
|
|
||||||
- />
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
DrawerContent = React.memo(DrawerContent)
|
|
||||||
-export {DrawerContent}
|
|
||||||
-
|
|
||||||
-let DrawerFooter = ({
|
|
||||||
- onPressFeedback,
|
|
||||||
- onPressHelp,
|
|
||||||
-}: {
|
|
||||||
- onPressFeedback: () => void
|
|
||||||
- onPressHelp: () => void
|
|
||||||
-}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
- const insets = useSafeAreaInsets()
|
|
||||||
- return (
|
|
||||||
- <View
|
|
||||||
- style={[
|
|
||||||
- a.flex_row,
|
|
||||||
- a.gap_sm,
|
|
||||||
- a.flex_wrap,
|
|
||||||
- a.pl_xl,
|
|
||||||
- a.pt_md,
|
|
||||||
- {
|
|
||||||
- paddingBottom: Math.max(
|
|
||||||
- insets.bottom + tokens.space.xs,
|
|
||||||
- tokens.space.xl,
|
|
||||||
- ),
|
|
||||||
- },
|
|
||||||
- ]}>
|
|
||||||
- <Button
|
|
||||||
- label={_(msg`Send feedback`)}
|
|
||||||
- size="small"
|
|
||||||
- variant="solid"
|
|
||||||
- color="secondary"
|
|
||||||
- onPress={onPressFeedback}>
|
|
||||||
- <ButtonIcon icon={Message} position="left" />
|
|
||||||
- <ButtonText>
|
|
||||||
- <Trans>Feedback</Trans>
|
|
||||||
- </ButtonText>
|
|
||||||
- </Button>
|
|
||||||
- <Button
|
|
||||||
- label={_(msg`Get help`)}
|
|
||||||
- size="small"
|
|
||||||
- variant="outline"
|
|
||||||
- color="secondary"
|
|
||||||
- onPress={onPressHelp}
|
|
||||||
- style={{
|
|
||||||
- backgroundColor: 'transparent',
|
|
||||||
- }}>
|
|
||||||
- <ButtonText>
|
|
||||||
- <Trans>Help</Trans>
|
|
||||||
- </ButtonText>
|
|
||||||
- </Button>
|
|
||||||
- </View>
|
|
||||||
- )
|
|
||||||
-}
|
|
||||||
-DrawerFooter = React.memo(DrawerFooter)
|
|
||||||
+export { DrawerContent }
|
|
||||||
|
|
||||||
interface MenuItemProps extends ComponentProps<typeof PressableScale> {
|
|
||||||
icon: JSX.Element
|
|
||||||
@@ -400,7 +250,7 @@ let SearchMenuItem = ({
|
|
||||||
isActive: boolean
|
|
||||||
onPress: () => void
|
|
||||||
}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
@@ -426,7 +276,7 @@ let HomeMenuItem = ({
|
|
||||||
isActive: boolean
|
|
||||||
onPress: () => void
|
|
||||||
}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
@@ -445,32 +295,6 @@ let HomeMenuItem = ({
|
|
||||||
}
|
|
||||||
HomeMenuItem = React.memo(HomeMenuItem)
|
|
||||||
|
|
||||||
-let ChatMenuItem = ({
|
|
||||||
- isActive,
|
|
||||||
- onPress,
|
|
||||||
-}: {
|
|
||||||
- isActive: boolean
|
|
||||||
- onPress: () => void
|
|
||||||
-}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
- const t = useTheme()
|
|
||||||
- return (
|
|
||||||
- <MenuItem
|
|
||||||
- icon={
|
|
||||||
- isActive ? (
|
|
||||||
- <MessageFilled style={[t.atoms.text]} width={iconWidth} />
|
|
||||||
- ) : (
|
|
||||||
- <Message style={[t.atoms.text]} width={iconWidth} />
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
- label={_(msg`Chat`)}
|
|
||||||
- bold={isActive}
|
|
||||||
- onPress={onPress}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
-}
|
|
||||||
-ChatMenuItem = React.memo(ChatMenuItem)
|
|
||||||
-
|
|
||||||
let NotificationsMenuItem = ({
|
|
||||||
isActive,
|
|
||||||
onPress,
|
|
||||||
@@ -478,7 +302,7 @@ let NotificationsMenuItem = ({
|
|
||||||
isActive: boolean
|
|
||||||
onPress: () => void
|
|
||||||
}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
const numUnreadNotifications = useUnreadNotifications()
|
|
||||||
return (
|
|
||||||
@@ -495,11 +319,11 @@ let NotificationsMenuItem = ({
|
|
||||||
numUnreadNotifications === ''
|
|
||||||
? ''
|
|
||||||
: _(
|
|
||||||
- msg`${plural(numUnreadNotifications ?? 0, {
|
|
||||||
- one: '# unread item',
|
|
||||||
- other: '# unread items',
|
|
||||||
- })}` || '',
|
|
||||||
- )
|
|
||||||
+ msg`${plural(numUnreadNotifications ?? 0, {
|
|
||||||
+ one: '# unread item',
|
|
||||||
+ other: '# unread items',
|
|
||||||
+ })}` || '',
|
|
||||||
+ )
|
|
||||||
}
|
|
||||||
count={numUnreadNotifications}
|
|
||||||
bold={isActive}
|
|
||||||
@@ -509,72 +333,6 @@ let NotificationsMenuItem = ({
|
|
||||||
}
|
|
||||||
NotificationsMenuItem = React.memo(NotificationsMenuItem)
|
|
||||||
|
|
||||||
-let FeedsMenuItem = ({
|
|
||||||
- isActive,
|
|
||||||
- onPress,
|
|
||||||
-}: {
|
|
||||||
- isActive: boolean
|
|
||||||
- onPress: () => void
|
|
||||||
-}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
- const t = useTheme()
|
|
||||||
- return (
|
|
||||||
- <MenuItem
|
|
||||||
- icon={
|
|
||||||
- isActive ? (
|
|
||||||
- <HashtagFilled width={iconWidth} style={[t.atoms.text]} />
|
|
||||||
- ) : (
|
|
||||||
- <Hashtag width={iconWidth} style={[t.atoms.text]} />
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
- label={_(msg`Feeds`)}
|
|
||||||
- bold={isActive}
|
|
||||||
- onPress={onPress}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
-}
|
|
||||||
-FeedsMenuItem = React.memo(FeedsMenuItem)
|
|
||||||
-
|
|
||||||
-let ListsMenuItem = ({onPress}: {onPress: () => void}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
- const t = useTheme()
|
|
||||||
-
|
|
||||||
- return (
|
|
||||||
- <MenuItem
|
|
||||||
- icon={<List style={[t.atoms.text]} width={iconWidth} />}
|
|
||||||
- label={_(msg`Lists`)}
|
|
||||||
- onPress={onPress}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
-}
|
|
||||||
-ListsMenuItem = React.memo(ListsMenuItem)
|
|
||||||
-
|
|
||||||
-let BookmarksMenuItem = ({
|
|
||||||
- isActive,
|
|
||||||
- onPress,
|
|
||||||
-}: {
|
|
||||||
- isActive: boolean
|
|
||||||
- onPress: () => void
|
|
||||||
-}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
- const t = useTheme()
|
|
||||||
-
|
|
||||||
- return (
|
|
||||||
- <MenuItem
|
|
||||||
- icon={
|
|
||||||
- isActive ? (
|
|
||||||
- <BookmarkFilled style={[t.atoms.text]} width={iconWidth} />
|
|
||||||
- ) : (
|
|
||||||
- <Bookmark style={[t.atoms.text]} width={iconWidth} />
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
- label={_(msg({message: 'Saved', context: 'link to bookmarks screen'}))}
|
|
||||||
- onPress={onPress}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
-}
|
|
||||||
-BookmarksMenuItem = React.memo(BookmarksMenuItem)
|
|
||||||
-
|
|
||||||
let ProfileMenuItem = ({
|
|
||||||
isActive,
|
|
||||||
onPress,
|
|
||||||
@@ -582,7 +340,7 @@ let ProfileMenuItem = ({
|
|
||||||
isActive: boolean
|
|
||||||
onPress: () => void
|
|
||||||
}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
@@ -600,8 +358,8 @@ let ProfileMenuItem = ({
|
|
||||||
}
|
|
||||||
ProfileMenuItem = React.memo(ProfileMenuItem)
|
|
||||||
|
|
||||||
-let SettingsMenuItem = ({onPress}: {onPress: () => void}): React.ReactNode => {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+let SettingsMenuItem = ({ onPress }: { onPress: () => void }): React.ReactNode => {
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<MenuItem
|
|
||||||
@@ -613,7 +371,7 @@ let SettingsMenuItem = ({onPress}: {onPress: () => void}): React.ReactNode => {
|
|
||||||
}
|
|
||||||
SettingsMenuItem = React.memo(SettingsMenuItem)
|
|
||||||
|
|
||||||
-function MenuItem({icon, label, count, bold, onPress}: MenuItemProps) {
|
|
||||||
+function MenuItem({ icon, label, count, bold, onPress }: MenuItemProps) {
|
|
||||||
const t = useTheme()
|
|
||||||
return (
|
|
||||||
<Button
|
|
||||||
@@ -621,7 +379,7 @@ function MenuItem({icon, label, count, bold, onPress}: MenuItemProps) {
|
|
||||||
onPress={onPress}
|
|
||||||
accessibilityRole="tab"
|
|
||||||
label={label}>
|
|
||||||
- {({hovered, pressed}) => (
|
|
||||||
+ {({ hovered, pressed }) => (
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
a.flex_1,
|
|
||||||
@@ -640,7 +398,7 @@ function MenuItem({icon, label, count, bold, onPress}: MenuItemProps) {
|
|
||||||
a.absolute,
|
|
||||||
a.inset_0,
|
|
||||||
a.align_end,
|
|
||||||
- {top: -4, right: a.gap_sm.gap * -1},
|
|
||||||
+ { top: -4, right: a.gap_sm.gap * -1 },
|
|
||||||
]}>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
@@ -686,37 +444,28 @@ function MenuItem({icon, label, count, bold, onPress}: MenuItemProps) {
|
|
||||||
}
|
|
||||||
|
|
||||||
function ExtraLinks() {
|
|
||||||
- const {_} = useLingui()
|
|
||||||
+ const { _ } = useLingui()
|
|
||||||
const t = useTheme()
|
|
||||||
const kawaii = useKawaiiMode()
|
|
||||||
+ const navigation = useNavigation<NavigationProp>()
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={[a.flex_col, a.gap_md, a.flex_wrap]}>
|
|
||||||
- <InlineLinkText
|
|
||||||
- style={[a.text_md]}
|
|
||||||
- label={_(msg`Terms of Service`)}
|
|
||||||
- to="https://bsky.social/about/support/tos">
|
|
||||||
- <Trans>Terms of Service</Trans>
|
|
||||||
- </InlineLinkText>
|
|
||||||
- <InlineLinkText
|
|
||||||
- style={[a.text_md]}
|
|
||||||
- to="https://bsky.social/about/support/privacy-policy"
|
|
||||||
- label={_(msg`Privacy Policy`)}>
|
|
||||||
- <Trans>Privacy Policy</Trans>
|
|
||||||
- </InlineLinkText>
|
|
||||||
- {kawaii && (
|
|
||||||
- <Text style={t.atoms.text_contrast_medium}>
|
|
||||||
- <Trans>
|
|
||||||
- Logo by{' '}
|
|
||||||
- <InlineLinkText
|
|
||||||
- style={[a.text_md]}
|
|
||||||
- to="/profile/sawaratsuki.bsky.social"
|
|
||||||
- label="@sawaratsuki.bsky.social">
|
|
||||||
- @sawaratsuki.bsky.social
|
|
||||||
- </InlineLinkText>
|
|
||||||
- </Trans>
|
|
||||||
+ <TouchableOpacity onPress={() => navigation.navigate('TermsOfService')}>
|
|
||||||
+ <Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
|
||||||
+ <Trans>Terms of Service</Trans>
|
|
||||||
</Text>
|
</Text>
|
||||||
- )}
|
</TouchableOpacity>
|
||||||
+ </TouchableOpacity>
|
|
||||||
+ <TouchableOpacity onPress={() => navigation.navigate('PrivacyPolicy')}>
|
|
||||||
+ <Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
|
||||||
+ <Trans>Privacy Policy</Trans>
|
|
||||||
+ </Text>
|
|
||||||
+ </TouchableOpacity>
|
|
||||||
+ <TouchableOpacity onPress={() => navigation.navigate('License')}>
|
+ <TouchableOpacity onPress={() => navigation.navigate('License')}>
|
||||||
+ <Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
+ <Text style={[a.text_md, t.atoms.text_contrast_medium]}>
|
||||||
+ <Trans>License</Trans>
|
+ <Trans>License</Trans>
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
diff --git a/src/view/com/auth/SplashScreen.tsx b/src/view/com/auth/SplashScreen.tsx
|
||||||
|
index 3442d1bdf..dd2d1fdfb 100644
|
||||||
|
--- a/src/view/com/auth/SplashScreen.tsx
|
||||||
|
+++ b/src/view/com/auth/SplashScreen.tsx
|
||||||
|
@@ -102,6 +102,17 @@ export const SplashScreen = ({
|
||||||
|
<AppLanguageDropdown />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
+ <View
|
||||||
|
+ style={[
|
||||||
|
+ a.px_lg,
|
||||||
|
+ a.pb_xl,
|
||||||
|
+ a.justify_center,
|
||||||
|
+ a.align_center,
|
||||||
|
+ ]}>
|
||||||
|
+ <Text style={[a.text_xs, t.atoms.text_contrast_low]}>
|
||||||
|
+ © syui
|
||||||
|
+ </Text>
|
||||||
|
+ </View>
|
||||||
|
<View style={{height: insets.bottom}} />
|
||||||
|
</ErrorBoundary>
|
||||||
|
</Animated.View>
|
||||||
|
|||||||
@@ -1,7 +1,73 @@
|
|||||||
diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx
|
diff --git a/src/screens/Settings/AboutSettings.tsx b/src/screens/Settings/AboutSettings.tsx
|
||||||
index 6b8257b91..e21b4900d 100644
|
index 6b8257b91..db64d6a69 100644
|
||||||
--- a/src/screens/Settings/AboutSettings.tsx
|
--- a/src/screens/Settings/AboutSettings.tsx
|
||||||
+++ b/src/screens/Settings/AboutSettings.tsx
|
+++ b/src/screens/Settings/AboutSettings.tsx
|
||||||
|
@@ -1,40 +1,40 @@
|
||||||
|
-import {useMemo} from 'react'
|
||||||
|
-import {Platform} from 'react-native'
|
||||||
|
-import {setStringAsync} from 'expo-clipboard'
|
||||||
|
+import { useMemo } from 'react'
|
||||||
|
+import { Platform } from 'react-native'
|
||||||
|
+import { setStringAsync } from 'expo-clipboard'
|
||||||
|
import * as FileSystem from 'expo-file-system/legacy'
|
||||||
|
-import {Image} from 'expo-image'
|
||||||
|
-import {msg, Trans} from '@lingui/macro'
|
||||||
|
-import {useLingui} from '@lingui/react'
|
||||||
|
-import {type NativeStackScreenProps} from '@react-navigation/native-stack'
|
||||||
|
-import {useMutation} from '@tanstack/react-query'
|
||||||
|
-import {Statsig} from 'statsig-react-native-expo'
|
||||||
|
+import { Image } from 'expo-image'
|
||||||
|
+import { msg, Trans } from '@lingui/macro'
|
||||||
|
+import { useLingui } from '@lingui/react'
|
||||||
|
+import { type NativeStackScreenProps } from '@react-navigation/native-stack'
|
||||||
|
+import { useMutation } from '@tanstack/react-query'
|
||||||
|
+import { Statsig } from 'statsig-react-native-expo'
|
||||||
|
|
||||||
|
-import {STATUS_PAGE_URL} from '#/lib/constants'
|
||||||
|
-import {type CommonNavigatorParams} from '#/lib/routes/types'
|
||||||
|
-import {isAndroid, isIOS, isNative} from '#/platform/detection'
|
||||||
|
+import { STATUS_PAGE_URL } from '#/lib/constants'
|
||||||
|
+import { type CommonNavigatorParams } from '#/lib/routes/types'
|
||||||
|
+import { isAndroid, isIOS, isNative } from '#/platform/detection'
|
||||||
|
import * as Toast from '#/view/com/util/Toast'
|
||||||
|
import * as SettingsList from '#/screens/Settings/components/SettingsList'
|
||||||
|
-import {Atom_Stroke2_Corner0_Rounded as AtomIcon} from '#/components/icons/Atom'
|
||||||
|
-import {BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon} from '#/components/icons/BroomSparkle'
|
||||||
|
-import {CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon} from '#/components/icons/CodeLines'
|
||||||
|
-import {Globe_Stroke2_Corner0_Rounded as GlobeIcon} from '#/components/icons/Globe'
|
||||||
|
-import {Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon} from '#/components/icons/Newspaper'
|
||||||
|
-import {Wrench_Stroke2_Corner2_Rounded as WrenchIcon} from '#/components/icons/Wrench'
|
||||||
|
+import { Atom_Stroke2_Corner0_Rounded as AtomIcon } from '#/components/icons/Atom'
|
||||||
|
+import { BroomSparkle_Stroke2_Corner2_Rounded as BroomSparkleIcon } from '#/components/icons/BroomSparkle'
|
||||||
|
+import { CodeLines_Stroke2_Corner2_Rounded as CodeLinesIcon } from '#/components/icons/CodeLines'
|
||||||
|
+import { Globe_Stroke2_Corner0_Rounded as GlobeIcon } from '#/components/icons/Globe'
|
||||||
|
+import { Newspaper_Stroke2_Corner2_Rounded as NewspaperIcon } from '#/components/icons/Newspaper'
|
||||||
|
+import { Wrench_Stroke2_Corner2_Rounded as WrenchIcon } from '#/components/icons/Wrench'
|
||||||
|
import * as Layout from '#/components/Layout'
|
||||||
|
-import {Loader} from '#/components/Loader'
|
||||||
|
+import { Loader } from '#/components/Loader'
|
||||||
|
import * as env from '#/env'
|
||||||
|
-import {useDemoMode} from '#/storage/hooks/demo-mode'
|
||||||
|
-import {useDevMode} from '#/storage/hooks/dev-mode'
|
||||||
|
-import {OTAInfo} from './components/OTAInfo'
|
||||||
|
+import { useDemoMode } from '#/storage/hooks/demo-mode'
|
||||||
|
+import { useDevMode } from '#/storage/hooks/dev-mode'
|
||||||
|
+import { OTAInfo } from './components/OTAInfo'
|
||||||
|
|
||||||
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AboutSettings'>
|
||||||
|
-export function AboutSettingsScreen({}: Props) {
|
||||||
|
- const {_, i18n} = useLingui()
|
||||||
|
+export function AboutSettingsScreen({ }: Props) {
|
||||||
|
+ const { _, i18n } = useLingui()
|
||||||
|
const [devModeEnabled, setDevModeEnabled] = useDevMode()
|
||||||
|
const [demoModeEnabled, setDemoModeEnabled] = useDemoMode()
|
||||||
|
const stableID = useMemo(() => Statsig.getStableID(), [])
|
||||||
|
|
||||||
|
- const {mutate: onClearImageCache, isPending: isClearingImageCache} =
|
||||||
|
+ const { mutate: onClearImageCache, isPending: isClearingImageCache } =
|
||||||
|
useMutation({
|
||||||
|
mutationFn: async () => {
|
||||||
|
const freeSpaceBefore = await FileSystem.getFreeDiskStorageAsync()
|
||||||
@@ -80,7 +80,7 @@ export function AboutSettingsScreen({}: Props) {
|
@@ -80,7 +80,7 @@ export function AboutSettingsScreen({}: Props) {
|
||||||
<Layout.Content>
|
<Layout.Content>
|
||||||
<SettingsList.Container>
|
<SettingsList.Container>
|
||||||
@@ -11,19 +77,11 @@ index 6b8257b91..e21b4900d 100644
|
|||||||
label={_(msg`Terms of Service`)}>
|
label={_(msg`Terms of Service`)}>
|
||||||
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
||||||
<SettingsList.ItemText>
|
<SettingsList.ItemText>
|
||||||
@@ -88,13 +88,21 @@ export function AboutSettingsScreen({}: Props) {
|
@@ -88,7 +88,15 @@ export function AboutSettingsScreen({}: Props) {
|
||||||
</SettingsList.ItemText>
|
</SettingsList.ItemText>
|
||||||
</SettingsList.LinkItem>
|
</SettingsList.LinkItem>
|
||||||
<SettingsList.LinkItem
|
<SettingsList.LinkItem
|
||||||
- to="https://bsky.social/about/support/privacy-policy"
|
- to="https://bsky.social/about/support/privacy-policy"
|
||||||
+ to="https://syu.is/about/support/privacy-policy"
|
|
||||||
label={_(msg`Privacy Policy`)}>
|
|
||||||
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
|
||||||
<SettingsList.ItemText>
|
|
||||||
<Trans>Privacy Policy</Trans>
|
|
||||||
</SettingsList.ItemText>
|
|
||||||
</SettingsList.LinkItem>
|
|
||||||
+ <SettingsList.LinkItem
|
|
||||||
+ to="/support/license"
|
+ to="/support/license"
|
||||||
+ label={_(msg`License`)}>
|
+ label={_(msg`License`)}>
|
||||||
+ <SettingsList.ItemIcon icon={NewspaperIcon} />
|
+ <SettingsList.ItemIcon icon={NewspaperIcon} />
|
||||||
@@ -31,6 +89,45 @@ index 6b8257b91..e21b4900d 100644
|
|||||||
+ <Trans>License</Trans>
|
+ <Trans>License</Trans>
|
||||||
+ </SettingsList.ItemText>
|
+ </SettingsList.ItemText>
|
||||||
+ </SettingsList.LinkItem>
|
+ </SettingsList.LinkItem>
|
||||||
<SettingsList.LinkItem
|
+ <SettingsList.LinkItem
|
||||||
to={STATUS_PAGE_URL}
|
+ to="https://syu.is/about/support/privacy-policy"
|
||||||
label={_(msg`Status Page`)}>
|
label={_(msg`Privacy Policy`)}>
|
||||||
|
<SettingsList.ItemIcon icon={NewspaperIcon} />
|
||||||
|
<SettingsList.ItemText>
|
||||||
|
@@ -131,17 +139,17 @@ export function AboutSettingsScreen({}: Props) {
|
||||||
|
Toast.show(
|
||||||
|
newDevModeEnabled
|
||||||
|
? _(
|
||||||
|
- msg({
|
||||||
|
- message: 'Developer mode enabled',
|
||||||
|
- context: 'toast',
|
||||||
|
- }),
|
||||||
|
- )
|
||||||
|
+ msg({
|
||||||
|
+ message: 'Developer mode enabled',
|
||||||
|
+ context: 'toast',
|
||||||
|
+ }),
|
||||||
|
+ )
|
||||||
|
: _(
|
||||||
|
- msg({
|
||||||
|
- message: 'Developer mode disabled',
|
||||||
|
- context: 'toast',
|
||||||
|
- }),
|
||||||
|
- ),
|
||||||
|
+ msg({
|
||||||
|
+ message: 'Developer mode disabled',
|
||||||
|
+ context: 'toast',
|
||||||
|
+ }),
|
||||||
|
+ ),
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
onPress={() => {
|
||||||
|
@@ -166,7 +174,7 @@ export function AboutSettingsScreen({}: Props) {
|
||||||
|
setDemoModeEnabled(newDemoModeEnabled)
|
||||||
|
Toast.show(
|
||||||
|
'Demo mode ' +
|
||||||
|
- (newDemoModeEnabled ? 'enabled' : 'disabled'),
|
||||||
|
+ (newDemoModeEnabled ? 'enabled' : 'disabled'),
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
label={
|
||||||
|
|||||||
@@ -1,6 +1,19 @@
|
|||||||
|
diff --git a/plugins/notificationsExtension/withNotificationsExtension.js b/plugins/notificationsExtension/withNotificationsExtension.js
|
||||||
|
index 6a00cfd23..f91decc08 100644
|
||||||
|
--- a/plugins/notificationsExtension/withNotificationsExtension.js
|
||||||
|
+++ b/plugins/notificationsExtension/withNotificationsExtension.js
|
||||||
|
@@ -10,7 +10,7 @@ const EXTENSION_NAME = 'BlueskyNSE'
|
||||||
|
const EXTENSION_CONTROLLER_NAME = 'NotificationService'
|
||||||
|
|
||||||
|
const withNotificationsExtension = config => {
|
||||||
|
- const soundFiles = ['dm.aiff']
|
||||||
|
+ const soundFiles = []
|
||||||
|
|
||||||
|
return withPlugins(config, [
|
||||||
|
// IOS
|
||||||
diff --git a/plugins/withCodeSignEntitlements.js b/plugins/withCodeSignEntitlements.js
|
diff --git a/plugins/withCodeSignEntitlements.js b/plugins/withCodeSignEntitlements.js
|
||||||
new file mode 100644
|
new file mode 100644
|
||||||
index 0000000..e69de29
|
index 000000000..b03b6bd68
|
||||||
--- /dev/null
|
--- /dev/null
|
||||||
+++ b/plugins/withCodeSignEntitlements.js
|
+++ b/plugins/withCodeSignEntitlements.js
|
||||||
@@ -0,0 +1,25 @@
|
@@ -0,0 +1,25 @@
|
||||||
|
|||||||
@@ -1,47 +1,8 @@
|
|||||||
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
|
diff --git a/src/view/screens/Home.tsx b/src/view/screens/Home.tsx
|
||||||
index e058e2883..03d7dc990 100644
|
index e058e2883..e762b1418 100644
|
||||||
--- a/src/view/screens/Home.tsx
|
--- a/src/view/screens/Home.tsx
|
||||||
+++ b/src/view/screens/Home.tsx
|
+++ b/src/view/screens/Home.tsx
|
||||||
@@ -1,23 +1,16 @@
|
@@ -39,6 +39,16 @@ import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
|
||||||
import React from 'react'
|
|
||||||
import {ActivityIndicator, StyleSheet} from 'react-native'
|
|
||||||
import {useFocusEffect} from '@react-navigation/native'
|
|
||||||
-
|
|
||||||
import {PROD_DEFAULT_FEED} from '#/lib/constants'
|
|
||||||
import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback'
|
|
||||||
import {useOTAUpdates} from '#/lib/hooks/useOTAUpdates'
|
|
||||||
import {useSetTitle} from '#/lib/hooks/useSetTitle'
|
|
||||||
import {useRequestNotificationsPermission} from '#/lib/notifications/notifications'
|
|
||||||
-import {
|
|
||||||
- type HomeTabNavigatorParams,
|
|
||||||
- type NativeStackScreenProps,
|
|
||||||
-} from '#/lib/routes/types'
|
|
||||||
+import {type HomeTabNavigatorParams, type NativeStackScreenProps} from '#/lib/routes/types'
|
|
||||||
import {logEvent} from '#/lib/statsig/statsig'
|
|
||||||
import {isWeb} from '#/platform/detection'
|
|
||||||
import {emitSoftReset} from '#/state/events'
|
|
||||||
-import {
|
|
||||||
- type SavedFeedSourceInfo,
|
|
||||||
- usePinnedFeedsInfos,
|
|
||||||
-} from '#/state/queries/feed'
|
|
||||||
+import {type SavedFeedSourceInfo, usePinnedFeedsInfos} from '#/state/queries/feed'
|
|
||||||
import {type FeedDescriptor, type FeedParams} from '#/state/queries/post-feed'
|
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
|
||||||
import {type UsePreferencesQueryResponse} from '#/state/queries/preferences/types'
|
|
||||||
@@ -27,11 +20,7 @@ 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,
|
|
||||||
- type PagerRef,
|
|
||||||
- type RenderTabBarFnProps,
|
|
||||||
-} from '#/view/com/pager/Pager'
|
|
||||||
+import {Pager, type PagerRef, type 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'
|
|
||||||
@@ -39,97 +28,67 @@ import {NoFeedsPinned} from '#/screens/Home/NoFeedsPinned'
|
|
||||||
import * as Layout from '#/components/Layout'
|
import * as Layout from '#/components/Layout'
|
||||||
import {useDemoMode} from '#/storage/hooks/demo-mode'
|
import {useDemoMode} from '#/storage/hooks/demo-mode'
|
||||||
|
|
||||||
@@ -53,362 +14,8 @@ index e058e2883..03d7dc990 100644
|
|||||||
+ savedFeed: undefined,
|
+ savedFeed: undefined,
|
||||||
+ pinned: true,
|
+ pinned: true,
|
||||||
+}]
|
+}]
|
||||||
|
+
|
||||||
+
|
+
|
||||||
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'>
|
type Props = NativeStackScreenProps<HomeTabNavigatorParams, 'Home' | 'Start'>
|
||||||
export function HomeScreen(props: Props) {
|
export function HomeScreen(props: Props) {
|
||||||
const {setShowLoggedOut} = useLoggedOutViewControls()
|
const {setShowLoggedOut} = useLoggedOutViewControls()
|
||||||
const {data: preferences} = usePreferencesQuery()
|
|
||||||
const {currentAccount} = useSession()
|
|
||||||
- const {data: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
|
|
||||||
- usePinnedFeedsInfos()
|
|
||||||
+ const {data: pinnedFeedInfos} = usePinnedFeedsInfos()
|
|
||||||
+
|
|
||||||
+ const safePreferences = preferences || { feedViewPrefs: { lab_mergeFeedEnabled: false }, savedFeeds: [] } as any
|
|
||||||
+ const safePinnedFeedInfos = [{
|
|
||||||
+ feedDescriptor: 'following',
|
|
||||||
+ displayName: 'Following',
|
|
||||||
+ id: 'following',
|
|
||||||
+ type: 'feed',
|
|
||||||
+ savedFeed: undefined,
|
|
||||||
+ pinned: true,
|
|
||||||
+ }]
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (isWeb && !currentAccount) {
|
|
||||||
const getParams = new URLSearchParams(window.location.search)
|
|
||||||
const splash = getParams.get('splash')
|
|
||||||
- if (splash === 'true') {
|
|
||||||
- setShowLoggedOut(true)
|
|
||||||
- return
|
|
||||||
- }
|
|
||||||
+ if (splash === 'true') { setShowLoggedOut(true); return }
|
|
||||||
}
|
|
||||||
-
|
|
||||||
const params = props.route.params
|
|
||||||
- if (
|
|
||||||
- currentAccount &&
|
|
||||||
- props.route.name === 'Start' &&
|
|
||||||
- params?.name &&
|
|
||||||
- params?.rkey
|
|
||||||
- ) {
|
|
||||||
- props.navigation.navigate('StarterPack', {
|
|
||||||
- rkey: params.rkey,
|
|
||||||
- name: params.name,
|
|
||||||
- })
|
|
||||||
+ if (currentAccount && props.route.name === 'Start' && params?.name && params?.rkey) {
|
|
||||||
+ props.navigation.navigate('StarterPack', { rkey: params.rkey, name: params.name })
|
|
||||||
}
|
|
||||||
- }, [
|
|
||||||
- currentAccount,
|
|
||||||
- props.navigation,
|
|
||||||
- props.route.name,
|
|
||||||
- props.route.params,
|
|
||||||
- setShowLoggedOut,
|
|
||||||
- ])
|
|
||||||
+ }, [currentAccount, props.navigation, props.route.name, props.route.params, setShowLoggedOut])
|
|
||||||
|
|
||||||
- if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
|
|
||||||
- return (
|
|
||||||
- <Layout.Screen testID="HomeScreen">
|
|
||||||
- <HomeScreenReady
|
|
||||||
- {...props}
|
|
||||||
- preferences={preferences}
|
|
||||||
- pinnedFeedInfos={pinnedFeedInfos}
|
|
||||||
- />
|
|
||||||
- </Layout.Screen>
|
|
||||||
- )
|
|
||||||
- } else {
|
|
||||||
- return (
|
|
||||||
- <Layout.Screen>
|
|
||||||
- <Layout.Center style={styles.loading}>
|
|
||||||
- <ActivityIndicator size="large" />
|
|
||||||
- </Layout.Center>
|
|
||||||
- </Layout.Screen>
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
+ return (
|
|
||||||
+ <Layout.Screen testID="HomeScreen">
|
|
||||||
+ <HomeScreenReady {...props} preferences={safePreferences} pinnedFeedInfos={safePinnedFeedInfos as any} />
|
|
||||||
+ </Layout.Screen>
|
|
||||||
+ )
|
|
||||||
}
|
|
||||||
|
|
||||||
-function HomeScreenReady({
|
|
||||||
- preferences,
|
|
||||||
- pinnedFeedInfos,
|
|
||||||
-}: Props & {
|
|
||||||
- preferences: UsePreferencesQueryResponse
|
|
||||||
- pinnedFeedInfos: SavedFeedSourceInfo[]
|
|
||||||
-}) {
|
|
||||||
- const allFeeds = React.useMemo(
|
|
||||||
- () => pinnedFeedInfos.map(f => f.feedDescriptor),
|
|
||||||
- [pinnedFeedInfos],
|
|
||||||
- )
|
|
||||||
- const maybeRawSelectedFeed: FeedDescriptor | undefined =
|
|
||||||
- useSelectedFeed() ?? allFeeds[0]
|
|
||||||
+function HomeScreenReady({preferences, pinnedFeedInfos}: any) {
|
|
||||||
+ const allFeeds = React.useMemo(() => pinnedFeedInfos.map(f => f.feedDescriptor), [pinnedFeedInfos])
|
|
||||||
+ const maybeRawSelectedFeed = useSelectedFeed() ?? allFeeds[0]
|
|
||||||
const setSelectedFeed = useSetSelectedFeed()
|
|
||||||
const maybeFoundIndex = allFeeds.indexOf(maybeRawSelectedFeed)
|
|
||||||
const selectedIndex = Math.max(0, maybeFoundIndex)
|
|
||||||
- const maybeSelectedFeed: FeedDescriptor | undefined = allFeeds[selectedIndex]
|
|
||||||
+ const maybeSelectedFeed = allFeeds[selectedIndex]
|
|
||||||
const requestNotificationsPermission = useRequestNotificationsPermission()
|
|
||||||
-
|
|
||||||
+
|
|
||||||
useSetTitle(pinnedFeedInfos[selectedIndex]?.displayName)
|
|
||||||
useOTAUpdates()
|
|
||||||
-
|
|
||||||
- React.useEffect(() => {
|
|
||||||
- requestNotificationsPermission('Home')
|
|
||||||
- }, [requestNotificationsPermission])
|
|
||||||
+ React.useEffect(() => { requestNotificationsPermission('Home') }, [requestNotificationsPermission])
|
|
||||||
|
|
||||||
const pagerRef = React.useRef<PagerRef>(null)
|
|
||||||
const lastPagerReportedIndexRef = React.useRef(selectedIndex)
|
|
||||||
React.useLayoutEffect(() => {
|
|
||||||
- // Since the pager is not a controlled component, adjust it imperatively
|
|
||||||
- // if the selected index gets out of sync with what it last reported.
|
|
||||||
- // This is supposed to only happen on the web when you use the right nav.
|
|
||||||
if (selectedIndex !== lastPagerReportedIndexRef.current) {
|
|
||||||
lastPagerReportedIndexRef.current = selectedIndex
|
|
||||||
pagerRef.current?.setPage(selectedIndex)
|
|
||||||
@@ -138,205 +97,43 @@ function HomeScreenReady({
|
|
||||||
|
|
||||||
const {hasSession} = useSession()
|
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
|
||||||
- useFocusEffect(
|
|
||||||
- React.useCallback(() => {
|
|
||||||
- setMinimalShellMode(false)
|
|
||||||
- }, [setMinimalShellMode]),
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- useFocusEffect(
|
|
||||||
- useNonReactiveCallback(() => {
|
|
||||||
- if (maybeSelectedFeed) {
|
|
||||||
- logEvent('home:feedDisplayed', {
|
|
||||||
- index: selectedIndex,
|
|
||||||
- feedType: maybeSelectedFeed.split('|')[0],
|
|
||||||
- feedUrl: maybeSelectedFeed,
|
|
||||||
- reason: 'focus',
|
|
||||||
- })
|
|
||||||
- }
|
|
||||||
- }),
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const onPageSelected = React.useCallback(
|
|
||||||
- (index: number) => {
|
|
||||||
- setMinimalShellMode(false)
|
|
||||||
- const maybeFeed = allFeeds[index]
|
|
||||||
-
|
|
||||||
- // Mutate the ref before setting state to avoid the imperative syncing effect
|
|
||||||
- // above from starting a loop on Android when swiping back and forth.
|
|
||||||
- lastPagerReportedIndexRef.current = index
|
|
||||||
- setSelectedFeed(maybeFeed)
|
|
||||||
-
|
|
||||||
- if (maybeFeed) {
|
|
||||||
- logEvent('home:feedDisplayed', {
|
|
||||||
- index,
|
|
||||||
- feedType: maybeFeed.split('|')[0],
|
|
||||||
- feedUrl: maybeFeed,
|
|
||||||
- })
|
|
||||||
- }
|
|
||||||
- },
|
|
||||||
- [setSelectedFeed, setMinimalShellMode, allFeeds],
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const onPressSelected = React.useCallback(() => {
|
|
||||||
- emitSoftReset()
|
|
||||||
- }, [])
|
|
||||||
-
|
|
||||||
- const onPageScrollStateChanged = React.useCallback(
|
|
||||||
- (state: 'idle' | 'dragging' | 'settling') => {
|
|
||||||
- 'worklet'
|
|
||||||
- if (state === 'dragging') {
|
|
||||||
- setMinimalShellMode(false)
|
|
||||||
- }
|
|
||||||
- },
|
|
||||||
- [setMinimalShellMode],
|
|
||||||
- )
|
|
||||||
+ useFocusEffect(React.useCallback(() => { setMinimalShellMode(false) }, [setMinimalShellMode]))
|
|
||||||
+
|
|
||||||
+ const onPageSelected = React.useCallback((index) => {
|
|
||||||
+ setMinimalShellMode(false)
|
|
||||||
+ const maybeFeed = allFeeds[index]
|
|
||||||
+ lastPagerReportedIndexRef.current = index
|
|
||||||
+ setSelectedFeed(maybeFeed)
|
|
||||||
+ }, [setSelectedFeed, setMinimalShellMode, allFeeds])
|
|
||||||
+
|
|
||||||
+ const onPressSelected = React.useCallback(() => { emitSoftReset() }, [])
|
|
||||||
+ const onPageScrollStateChanged = React.useCallback((state) => {
|
|
||||||
+ 'worklet'
|
|
||||||
+ if (state === 'dragging') setMinimalShellMode(false)
|
|
||||||
+ }, [setMinimalShellMode])
|
|
||||||
|
|
||||||
const [demoMode] = useDemoMode()
|
|
||||||
-
|
|
||||||
- const renderTabBar = React.useCallback(
|
|
||||||
- (props: RenderTabBarFnProps) => {
|
|
||||||
- if (demoMode) {
|
|
||||||
- return (
|
|
||||||
- <HomeHeader
|
|
||||||
- key="FEEDS_TAB_BAR"
|
|
||||||
- {...props}
|
|
||||||
- testID="homeScreenFeedTabs"
|
|
||||||
- onPressSelected={onPressSelected}
|
|
||||||
- // @ts-ignore
|
|
||||||
- feeds={[{displayName: 'Following'}, {displayName: 'Discover'}]}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
- return (
|
|
||||||
- <HomeHeader
|
|
||||||
- key="FEEDS_TAB_BAR"
|
|
||||||
- {...props}
|
|
||||||
- testID="homeScreenFeedTabs"
|
|
||||||
- onPressSelected={onPressSelected}
|
|
||||||
- feeds={pinnedFeedInfos}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
- },
|
|
||||||
- [onPressSelected, pinnedFeedInfos, demoMode],
|
|
||||||
- )
|
|
||||||
-
|
|
||||||
- const renderFollowingEmptyState = React.useCallback(() => {
|
|
||||||
- return <FollowingEmptyState />
|
|
||||||
- }, [])
|
|
||||||
-
|
|
||||||
- const renderCustomFeedEmptyState = React.useCallback(() => {
|
|
||||||
- return <CustomFeedEmptyState />
|
|
||||||
- }, [])
|
|
||||||
-
|
|
||||||
- const homeFeedParams = React.useMemo<FeedParams>(() => {
|
|
||||||
- return {
|
|
||||||
- mergeFeedEnabled: Boolean(preferences.feedViewPrefs.lab_mergeFeedEnabled),
|
|
||||||
- mergeFeedSources: preferences.feedViewPrefs.lab_mergeFeedEnabled
|
|
||||||
- ? preferences.savedFeeds
|
|
||||||
- .filter(f => f.type === 'feed' || f.type === 'list')
|
|
||||||
- .map(f => f.value)
|
|
||||||
- : [],
|
|
||||||
- }
|
|
||||||
- }, [preferences])
|
|
||||||
-
|
|
||||||
- if (demoMode) {
|
|
||||||
- return (
|
|
||||||
- <Pager
|
|
||||||
- ref={pagerRef}
|
|
||||||
- testID="homeScreen"
|
|
||||||
- onPageSelected={onPageSelected}
|
|
||||||
- onPageScrollStateChanged={onPageScrollStateChanged}
|
|
||||||
- renderTabBar={renderTabBar}
|
|
||||||
- initialPage={selectedIndex}>
|
|
||||||
- <FeedPage
|
|
||||||
- testID="demoFeedPage"
|
|
||||||
- isPageFocused
|
|
||||||
- isPageAdjacent={false}
|
|
||||||
- feed="demo"
|
|
||||||
- renderEmptyState={renderCustomFeedEmptyState}
|
|
||||||
- feedInfo={pinnedFeedInfos[0]}
|
|
||||||
- />
|
|
||||||
- <FeedPage
|
|
||||||
- testID="customFeedPage"
|
|
||||||
- isPageFocused
|
|
||||||
- isPageAdjacent={false}
|
|
||||||
- feed={`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`}
|
|
||||||
- renderEmptyState={renderCustomFeedEmptyState}
|
|
||||||
- feedInfo={pinnedFeedInfos[0]}
|
|
||||||
- />
|
|
||||||
- </Pager>
|
|
||||||
- )
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- return hasSession ? (
|
|
||||||
- <Pager
|
|
||||||
- key={allFeeds.join(',')}
|
|
||||||
- ref={pagerRef}
|
|
||||||
- testID="homeScreen"
|
|
||||||
- initialPage={selectedIndex}
|
|
||||||
- onPageSelected={onPageSelected}
|
|
||||||
- onPageScrollStateChanged={onPageScrollStateChanged}
|
|
||||||
- renderTabBar={renderTabBar}>
|
|
||||||
- {pinnedFeedInfos.length ? (
|
|
||||||
- pinnedFeedInfos.map((feedInfo, index) => {
|
|
||||||
+ const renderTabBar = React.useCallback((props) => {
|
|
||||||
+ return <HomeHeader key="FEEDS_TAB_BAR" {...props} testID="homeScreenFeedTabs" onPressSelected={onPressSelected} feeds={pinnedFeedInfos} />
|
|
||||||
+ }, [onPressSelected, pinnedFeedInfos])
|
|
||||||
+
|
|
||||||
+ const renderFollowingEmptyState = React.useCallback(() => <FollowingEmptyState />, [])
|
|
||||||
+ const renderCustomFeedEmptyState = React.useCallback(() => <CustomFeedEmptyState />, [])
|
|
||||||
+
|
|
||||||
+ const homeFeedParams = React.useMemo(() => ({
|
|
||||||
+ mergeFeedEnabled: false, mergeFeedSources: []
|
|
||||||
+ }), [preferences])
|
|
||||||
+
|
|
||||||
+ return (
|
|
||||||
+ <Pager ref={pagerRef} testID="homeScreen" initialPage={selectedIndex} onPageSelected={onPageSelected} onPageScrollStateChanged={onPageScrollStateChanged} renderTabBar={renderTabBar}>
|
|
||||||
+ {pinnedFeedInfos.map((feedInfo, index) => {
|
|
||||||
const feed = feedInfo.feedDescriptor
|
|
||||||
if (feed === 'following') {
|
|
||||||
- return (
|
|
||||||
- <FeedPage
|
|
||||||
- key={feed}
|
|
||||||
- testID="followingFeedPage"
|
|
||||||
- isPageFocused={maybeSelectedFeed === feed}
|
|
||||||
- isPageAdjacent={Math.abs(selectedIndex - index) === 1}
|
|
||||||
- feed={feed}
|
|
||||||
- feedParams={homeFeedParams}
|
|
||||||
- renderEmptyState={renderFollowingEmptyState}
|
|
||||||
- renderEndOfFeed={FollowingEndOfFeed}
|
|
||||||
- feedInfo={feedInfo}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
+ return <FeedPage key={feed} testID="followingFeedPage" isPageFocused={maybeSelectedFeed === feed} isPageAdjacent={Math.abs(selectedIndex - index) === 1} feed={feed} feedParams={homeFeedParams} renderEmptyState={renderFollowingEmptyState} renderEndOfFeed={FollowingEndOfFeed} feedInfo={feedInfo} />
|
|
||||||
}
|
|
||||||
- const savedFeedConfig = feedInfo.savedFeed
|
|
||||||
- return (
|
|
||||||
- <FeedPage
|
|
||||||
- key={feed}
|
|
||||||
- testID="customFeedPage"
|
|
||||||
- isPageFocused={maybeSelectedFeed === feed}
|
|
||||||
- isPageAdjacent={Math.abs(selectedIndex - index) === 1}
|
|
||||||
- feed={feed}
|
|
||||||
- renderEmptyState={renderCustomFeedEmptyState}
|
|
||||||
- savedFeedConfig={savedFeedConfig}
|
|
||||||
- feedInfo={feedInfo}
|
|
||||||
- />
|
|
||||||
- )
|
|
||||||
- })
|
|
||||||
- ) : (
|
|
||||||
- <NoFeedsPinned preferences={preferences} />
|
|
||||||
- )}
|
|
||||||
- </Pager>
|
|
||||||
- ) : (
|
|
||||||
- <Pager
|
|
||||||
- testID="homeScreen"
|
|
||||||
- onPageSelected={onPageSelected}
|
|
||||||
- onPageScrollStateChanged={onPageScrollStateChanged}
|
|
||||||
- renderTabBar={renderTabBar}>
|
|
||||||
- <FeedPage
|
|
||||||
- testID="customFeedPage"
|
|
||||||
- isPageFocused
|
|
||||||
- isPageAdjacent={false}
|
|
||||||
- feed={`feedgen|${PROD_DEFAULT_FEED('whats-hot')}`}
|
|
||||||
- renderEmptyState={renderCustomFeedEmptyState}
|
|
||||||
- feedInfo={pinnedFeedInfos[0]}
|
|
||||||
- />
|
|
||||||
+ return <FeedPage key={feed} testID="customFeedPage" isPageFocused={maybeSelectedFeed === feed} isPageAdjacent={Math.abs(selectedIndex - index) === 1} feed={feed} renderEmptyState={renderCustomFeedEmptyState} savedFeedConfig={feedInfo.savedFeed} feedInfo={feedInfo} />
|
|
||||||
+ })}
|
|
||||||
</Pager>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
-
|
|
||||||
-const styles = StyleSheet.create({
|
|
||||||
- loading: {
|
|
||||||
- height: '100%',
|
|
||||||
- alignContent: 'center',
|
|
||||||
- justifyContent: 'center',
|
|
||||||
- paddingBottom: 100,
|
|
||||||
- },
|
|
||||||
-})
|
|
||||||
+const styles = StyleSheet.create({ loading: { height: '100%', alignContent: 'center', justifyContent: 'center', paddingBottom: 100 } })
|
|
||||||
|
|||||||
@@ -138,6 +138,12 @@ function ios-copy-new-files() {
|
|||||||
echo "✅ Created assets/icon.png from assets/logo.png"
|
echo "✅ Created assets/icon.png from assets/logo.png"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Copy app-icons
|
||||||
|
if [ -d "$d/ios/app-icons" ]; then
|
||||||
|
cp -rf "$d/ios/app-icons" "$target_dir/assets/"
|
||||||
|
echo "✅ Copied app-icons"
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user