diff --git a/modules/BlueskyClip/ViewController.swift b/modules/BlueskyClip/ViewController.swift
index b178644b8f..5385ab7001 100644
--- a/modules/BlueskyClip/ViewController.swift
+++ b/modules/BlueskyClip/ViewController.swift
@@ -42,7 +42,7 @@ class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDele
let payload = try? JSONDecoder().decode(WebViewActionPayload.self, from: data) else {
return
}
-
+
switch payload.action {
case .present:
guard let url = self.starterPackUrl else {
@@ -66,23 +66,51 @@ class ViewController: UIViewController, WKScriptMessageHandler, WKNavigationDele
guard let url = navigationAction.request.url else {
return .allow
}
-
+
// Store the previous one to compare later, but only set starterPackUrl when we find the right one
prevUrl = url
// pathComponents starts with "/" as the first component, then each path name. so...
// ["/", "start", "name", "rkey"]
- if url.pathComponents.count == 4,
- url.pathComponents[1] == "start" {
+ if isStarterPackUrl(url){
self.starterPackUrl = url
}
-
+
return .allow
}
+
+ func isStarterPackUrl(_ url: URL) -> Bool {
+ var host: String?
+ if #available(iOS 16.0, *) {
+ host = url.host()
+ } else {
+ host = url.host
+ }
+
+ switch host {
+ case "bsky.app":
+ if url.pathComponents.count == 4,
+ (url.pathComponents[1] == "start" || url.pathComponents[1] == "starter-pack") {
+ return true
+ }
+ return false
+ case "go.bsky.app":
+ if url.pathComponents.count == 2 {
+ return true
+ }
+ return false
+ default:
+ return false
+ }
+ }
func handleURL(url: URL) {
- let urlString = "\(url.absoluteString)?clip=true"
- if let url = URL(string: urlString) {
- self.webView?.load(URLRequest(url: url))
+ if isStarterPackUrl(url) {
+ let urlString = "\(url.absoluteString)?clip=true"
+ if let url = URL(string: urlString) {
+ self.webView?.load(URLRequest(url: url))
+ }
+ } else {
+ self.webView?.load(URLRequest(url: URL(string: "https://bsky.app/?splash=true&clip=true")!))
}
}
diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx
index 6d859aeb0b..a27271168c 100644
--- a/src/components/Dialog/index.tsx
+++ b/src/components/Dialog/index.tsx
@@ -153,18 +153,18 @@ export function Outer({
)
return (
-
-
+
+
{children}
-
-
+
+
)
}
diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts
index caa787535b..b1388a817e 100644
--- a/src/components/Dialog/types.ts
+++ b/src/components/Dialog/types.ts
@@ -6,7 +6,6 @@ import type {
} from 'react-native'
import {ViewStyleProp} from '#/alf'
-import {PortalComponent} from '#/components/Portal'
import {BottomSheetViewProps} from '../../../modules/bottom-sheet'
import {BottomSheetSnapPoint} from '../../../modules/bottom-sheet/src/BottomSheet.types'
@@ -61,7 +60,6 @@ export type DialogOuterProps = {
nativeOptions?: Omit
webOptions?: {}
testID?: string
- Portal?: PortalComponent
}
type DialogInnerPropsBase = React.PropsWithChildren & T
diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx
index 12cf1866e5..4d35a63bdb 100644
--- a/src/components/Menu/index.tsx
+++ b/src/components/Menu/index.tsx
@@ -18,7 +18,6 @@ import {
ItemTextProps,
TriggerProps,
} from '#/components/Menu/types'
-import {PortalComponent} from '#/components/Portal'
import {Text} from '#/components/Typography'
export {
@@ -78,11 +77,9 @@ export function Trigger({children, label}: TriggerProps) {
export function Outer({
children,
showCancel,
- Portal,
}: React.PropsWithChildren<{
showCancel?: boolean
style?: StyleProp
- Portal?: PortalComponent
}>) {
const context = React.useContext(Context)
const {_} = useLingui()
@@ -90,8 +87,7 @@ export function Outer({
return (
+ nativeOptions={{preventExpansion: true}}>
{/* Re-wrap with context since Dialogs are portal-ed to root */}
diff --git a/src/components/Portal.tsx b/src/components/Portal.tsx
index 7441df005c..03b397b2b8 100644
--- a/src/components/Portal.tsx
+++ b/src/components/Portal.tsx
@@ -12,8 +12,6 @@ type ComponentMap = {
[id: string]: Component
}
-export type PortalComponent = ({children}: {children?: React.ReactNode}) => null
-
export function createPortalGroup() {
const Context = React.createContext({
outlet: null,
diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx
index c47f0d64af..7b33c6e256 100644
--- a/src/components/Prompt.tsx
+++ b/src/components/Prompt.tsx
@@ -6,7 +6,6 @@ import {useLingui} from '@lingui/react'
import {atoms as a, useBreakpoints, useTheme} from '#/alf'
import {Button, ButtonColor, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
-import {PortalComponent} from '#/components/Portal'
import {Text} from '#/components/Typography'
import {BottomSheetViewProps} from '../../modules/bottom-sheet'
@@ -27,12 +26,10 @@ export function Outer({
children,
control,
testID,
- Portal,
nativeOptions,
}: React.PropsWithChildren<{
control: Dialog.DialogControlProps
testID?: string
- Portal?: PortalComponent
nativeOptions?: Omit
}>) {
const {gtMobile} = useBreakpoints()
@@ -48,7 +45,6 @@ export function Outer({
@@ -190,7 +186,6 @@ export function Basic({
onConfirm,
confirmButtonColor,
showCancel = true,
- Portal,
}: React.PropsWithChildren<{
control: Dialog.DialogOuterProps['control']
title: string
@@ -207,10 +202,9 @@ export function Basic({
onConfirm: (e: GestureResponderEvent) => void
confirmButtonColor?: ButtonColor
showCancel?: boolean
- Portal?: PortalComponent
}>) {
return (
-
+
{title}
{description}
diff --git a/src/components/ReportDialog/index.tsx b/src/components/ReportDialog/index.tsx
index 5bf8aa5b4b..4402152abe 100644
--- a/src/components/ReportDialog/index.tsx
+++ b/src/components/ReportDialog/index.tsx
@@ -35,7 +35,7 @@ function ReportDialogInner(props: ReportDialogProps) {
isLoading: isLabelerLoading,
data: labelers,
error,
- } = useMyLabelersQuery()
+ } = useMyLabelersQuery({excludeNonConfigurableLabelers: true})
const isLoading = useDelayedLoading(500, isLabelerLoading)
const ref = React.useRef(null)
diff --git a/src/screens/StarterPack/StarterPackLandingScreen.tsx b/src/screens/StarterPack/StarterPackLandingScreen.tsx
index 68ff3aa7bc..ec31fc21d0 100644
--- a/src/screens/StarterPack/StarterPackLandingScreen.tsx
+++ b/src/screens/StarterPack/StarterPackLandingScreen.tsx
@@ -47,7 +47,7 @@ interface AppClipMessage {
jsonToStore?: string
}
-function postAppClipMessage(message: AppClipMessage) {
+export function postAppClipMessage(message: AppClipMessage) {
// @ts-expect-error safari webview only
window.webkit.messageHandlers.onMessage.postMessage(JSON.stringify(message))
}
@@ -356,7 +356,7 @@ function LandingScreenLoaded({
)
}
-function AppClipOverlay({
+export function AppClipOverlay({
visible,
setIsVisible,
}: {
diff --git a/src/state/queries/preferences/moderation.ts b/src/state/queries/preferences/moderation.ts
index 9cd183e8b1..1b4de8bf22 100644
--- a/src/state/queries/preferences/moderation.ts
+++ b/src/state/queries/preferences/moderation.ts
@@ -1,12 +1,13 @@
import React from 'react'
import {
- DEFAULT_LABEL_SETTINGS,
BskyAgent,
+ DEFAULT_LABEL_SETTINGS,
interpretLabelValueDefinitions,
} from '@atproto/api'
-import {usePreferencesQuery} from './index'
+import {isNonConfigurableModerationAuthority} from '#/state/session/additional-moderation-authorities'
import {useLabelersDetailedInfoQuery} from '../labeler'
+import {usePreferencesQuery} from './index'
/**
* More strict than our default settings for logged in users.
@@ -16,15 +17,22 @@ export const DEFAULT_LOGGED_OUT_LABEL_PREFERENCES: typeof DEFAULT_LABEL_SETTINGS
Object.entries(DEFAULT_LABEL_SETTINGS).map(([key, _pref]) => [key, 'hide']),
)
-export function useMyLabelersQuery() {
+export function useMyLabelersQuery({
+ excludeNonConfigurableLabelers = false,
+}: {
+ excludeNonConfigurableLabelers?: boolean
+} = {}) {
const prefs = usePreferencesQuery()
- const dids = Array.from(
+ let dids = Array.from(
new Set(
BskyAgent.appLabelers.concat(
prefs.data?.moderationPrefs.labelers.map(l => l.did) || [],
),
),
)
+ if (excludeNonConfigurableLabelers) {
+ dids = dids.filter(did => !isNonConfigurableModerationAuthority(did))
+ }
const labelers = useLabelersDetailedInfoQuery({dids})
const isLoading = prefs.isLoading || labelers.isLoading
const error = prefs.error || labelers.error
diff --git a/src/view/com/auth/SplashScreen.web.tsx b/src/view/com/auth/SplashScreen.web.tsx
index dee0d6b70a..e8a7c7373f 100644
--- a/src/view/com/auth/SplashScreen.web.tsx
+++ b/src/view/com/auth/SplashScreen.web.tsx
@@ -9,6 +9,10 @@ import {useKawaiiMode} from '#/state/preferences/kawaii'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
import {Logo} from '#/view/icons/Logo'
import {Logotype} from '#/view/icons/Logotype'
+import {
+ AppClipOverlay,
+ postAppClipMessage,
+} from '#/screens/StarterPack/StarterPackLandingScreen'
import {atoms as a, useTheme} from '#/alf'
import {AppLanguageDropdown} from '#/components/AppLanguageDropdown'
import {Button, ButtonText} from '#/components/Button'
@@ -28,6 +32,18 @@ export const SplashScreen = ({
const {_} = useLingui()
const t = useTheme()
const {isTabletOrMobile: isMobileWeb} = useWebMediaQueries()
+ const [showClipOverlay, setShowClipOverlay] = React.useState(false)
+
+ React.useEffect(() => {
+ const getParams = new URLSearchParams(window.location.search)
+ const clip = getParams.get('clip')
+ if (clip === 'true') {
+ setShowClipOverlay(true)
+ postAppClipMessage({
+ action: 'present',
+ })
+ }
+ }, [])
const kawaii = useKawaiiMode()
@@ -119,6 +135,10 @@ export const SplashScreen = ({
+
>
)
}
diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx
index b311f78879..dbd68f8ef5 100644
--- a/src/view/com/util/UserAvatar.tsx
+++ b/src/view/com/util/UserAvatar.tsx
@@ -30,7 +30,6 @@ import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
import {Link} from '#/components/Link'
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
import * as Menu from '#/components/Menu'
-import {PortalComponent} from '#/components/Portal'
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
@@ -51,7 +50,6 @@ interface UserAvatarProps extends BaseUserAvatarProps {
interface EditableUserAvatarProps extends BaseUserAvatarProps {
onSelectNewAvatar: (img: RNImage | null) => void
- Portal?: PortalComponent
}
interface PreviewableUserAvatarProps extends BaseUserAvatarProps {
@@ -268,7 +266,6 @@ let EditableUserAvatar = ({
size,
avatar,
onSelectNewAvatar,
- Portal,
}: EditableUserAvatarProps): React.ReactNode => {
const t = useTheme()
const pal = usePalette('default')
@@ -366,7 +363,7 @@ let EditableUserAvatar = ({
)}
-
+
{isNative && (
void
- Portal?: PortalComponent
}) {
const pal = usePalette('default')
const theme = useTheme()
@@ -118,7 +115,7 @@ export function UserBanner({
)}
-
+
{isNative && (
export function HomeScreen(props: Props) {
+ const {setShowLoggedOut} = useLoggedOutViewControls()
const {data: preferences} = usePreferencesQuery()
const {currentAccount} = useSession()
const {data: pinnedFeedInfos, isLoading: isPinnedFeedsLoading} =
usePinnedFeedsInfos()
React.useEffect(() => {
+ if (isWeb && !currentAccount) {
+ const getParams = new URLSearchParams(window.location.search)
+ const splash = getParams.get('splash')
+ if (splash === 'true') {
+ setShowLoggedOut(true)
+ return
+ }
+ }
+
const params = props.route.params
if (
currentAccount &&
@@ -45,7 +60,13 @@ export function HomeScreen(props: Props) {
name: params.name,
})
}
- }, [currentAccount, props.navigation, props.route.name, props.route.params])
+ }, [
+ currentAccount,
+ props.navigation,
+ props.route.name,
+ props.route.params,
+ setShowLoggedOut,
+ ])
if (preferences && pinnedFeedInfos && !isPinnedFeedsLoading) {
return (