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 = ({