diff --git a/ios/assets/favicons/atproto.com.png b/ios/assets/favicons/atproto.com.png new file mode 100644 index 0000000..4c04c29 Binary files /dev/null and b/ios/assets/favicons/atproto.com.png differ diff --git a/ios/assets/favicons/bsky.app.png b/ios/assets/favicons/bsky.app.png new file mode 100644 index 0000000..a5ca7ee Binary files /dev/null and b/ios/assets/favicons/bsky.app.png differ diff --git a/ios/assets/favicons/syui.ai.png b/ios/assets/favicons/syui.ai.png new file mode 100644 index 0000000..11f3bcd Binary files /dev/null and b/ios/assets/favicons/syui.ai.png differ diff --git a/ios/patching/038-social-app-ios-profile-services.patch b/ios/patching/038-social-app-ios-profile-services.patch new file mode 100644 index 0000000..a29a5ee --- /dev/null +++ b/ios/patching/038-social-app-ios-profile-services.patch @@ -0,0 +1,113 @@ +diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx +--- a/src/screens/Profile/Header/ProfileHeaderStandard.tsx ++++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx +@@ -1,25 +1,27 @@ + import {memo, useMemo, useState} from 'react' +-import {View} from 'react-native' ++import {Image, Pressable, View} from 'react-native' + import { + type AppBskyActorDefs, + moderateProfile, + type ModerationDecision, + type ModerationOpts, + type RichText as RichTextAPI, + } from '@atproto/api' + import {msg, Trans} from '@lingui/macro' + import {useLingui} from '@lingui/react' ++import {useQuery} from '@tanstack/react-query' + + import {useActorStatus} from '#/lib/actor-status' + import {useHaptics} from '#/lib/haptics' ++import {useOpenLink} from '#/lib/hooks/useOpenLink' + import {sanitizeDisplayName} from '#/lib/strings/display-names' + import {sanitizeHandle} from '#/lib/strings/handles' + import {logger} from '#/logger' + import {type Shadow, useProfileShadow} from '#/state/cache/profile-shadow' + import { + useProfileBlockMutationQueue, + useProfileFollowMutationQueue, + } from '#/state/queries/profile' +-import {useRequireAuth, useSession} from '#/state/session' ++import {useAgent, useRequireAuth, useSession} from '#/state/session' + import {ProfileMenu} from '#/view/com/profile/ProfileMenu' + import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf' +@@ -45,6 +47,71 @@ + import {ProfileHeaderShell} from './Shell' + import {AnimatedProfileHeaderSuggestedFollows} from './SuggestedFollows' + ++const SERVICE_FAVICONS: Record = { ++ 'syui.ai': require('../../../../assets/favicons/syui.ai.png'), ++ 'bsky.app': require('../../../../assets/favicons/bsky.app.png'), ++ 'atproto.com': require('../../../../assets/favicons/atproto.com.png'), ++} ++ ++function ProfileServiceLinks({ ++ profile, ++}: { ++ profile: AppBskyActorDefs.ProfileViewDetailed ++}) { ++ const t = useTheme() ++ const agent = useAgent() ++ const openLink = useOpenLink() ++ ++ const {data: services} = useQuery({ ++ queryKey: ['profile-services', profile.did], ++ queryFn: async () => { ++ const res = await agent.com.atproto.repo.describeRepo({ ++ repo: profile.did, ++ }) ++ const collections: string[] = res.data.collections || [] ++ const serviceSet = new Set() ++ for (const nsid of collections) { ++ const parts = nsid.split('.') ++ if (parts.length >= 2) { ++ const domain = parts.slice(0, 2).reverse().join('.') ++ serviceSet.add(domain) ++ } ++ } ++ return Array.from(serviceSet) ++ }, ++ }) ++ ++ if (!services || services.length === 0) return null ++ ++ return ( ++ ++ {services.map(service => ( ++ ++ openLink( ++ `https://syui.ai/@${profile.handle}/at/service/${service}`, ++ ) ++ } ++ style={[a.flex_row, a.align_center, a.gap_xs]}> ++ ++ ++ {service} ++ ++ ++ ))} ++ ++ ) ++} ++ + interface Props { + profile: AppBskyActorDefs.ProfileViewDetailed + descriptionRT: RichTextAPI | null +@@ -150,6 +217,7 @@ + {!isPlaceholderProfile && !isBlockedUser && ( + + ++ + {descriptionRT && !moderation.ui('profileView').blur ? ( + + +- ++ {false && ( ++ ++ )} + + + diff --git a/ios/setup.zsh b/ios/setup.zsh index 838f9c4..bbf94f4 100755 --- a/ios/setup.zsh +++ b/ios/setup.zsh @@ -45,6 +45,8 @@ PATCH_FILES_IOS=( "033-social-app-ios-hide-profile-tabs.patch" "036-social-app-ios-homeheader-loggedout.patch" "037-social-app-ios-disable-contacts-nux.patch" + "038-social-app-ios-profile-services.patch" + "039-social-app-ios-hide-feed-controls.patch" ) function ios-env() { diff --git a/patching/170-pds-oauth-same-site-fix.patch b/patching/170-pds-oauth-same-site-fix.patch index b836b59..3dd6248 100644 --- a/patching/170-pds-oauth-same-site-fix.patch +++ b/patching/170-pds-oauth-same-site-fix.patch @@ -1,13 +1,11 @@ diff --git a/packages/oauth/oauth-provider/src/router/create-authorization-page-middleware.ts b/packages/oauth/oauth-provider/src/router/create-authorization-page-middleware.ts -index f653b0353..45c45fac1 100644 --- a/packages/oauth/oauth-provider/src/router/create-authorization-page-middleware.ts +++ b/packages/oauth/oauth-provider/src/router/create-authorization-page-middleware.ts -@@ -53,7 +53,7 @@ export function createAuthorizationPageMiddleware< - res.setHeader('Cache-Control', 'no-store') - res.setHeader('Pragma', 'no-cache') - -- validateFetchSite(req, ['cross-site', 'none']) -+ validateFetchSite(req, ['cross-site', 'same-site', 'none']) +@@ -74,7 +74,7 @@ + // @TODO Consider removing this altogether to allow hosting PDS and app on + // the same site but different origins (different subdomains). +- validateFetchSite(req, ['same-origin', 'cross-site', 'none']) ++ validateFetchSite(req, ['same-origin', 'same-site', 'cross-site', 'none']) validateFetchMode(req, ['navigate']) validateFetchDest(req, ['document']) validateOrigin(req, issuerOrigin)