feat(mobile): enhance web view navigation and header interactions
- Add ModalWebViewController and WebViewController for improved web browsing - Implement WebViewManager method to push modal web views - Create UINavigationHeaderActionButton for consistent header button styling - Update header components to use new action button and back button components - Refactor navigation header and scroll view interactions Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
97dda3ed7d
commit
6c2bc6633e
|
|
@ -27,6 +27,13 @@ class ModalWebViewController: UIViewController {
|
|||
setupNavigationBar()
|
||||
setupWebView()
|
||||
loadContent()
|
||||
setupInteractivePopGesture()
|
||||
|
||||
}
|
||||
|
||||
private func setupInteractivePopGesture() {
|
||||
navigationController?.interactivePopGestureRecognizer?.delegate = self
|
||||
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
|
||||
}
|
||||
|
||||
private func setupNavigationBar() {
|
||||
|
|
@ -55,6 +62,7 @@ class ModalWebViewController: UIViewController {
|
|||
|
||||
private func setupWebView() {
|
||||
view.addSubview(webView)
|
||||
view.backgroundColor = .systemBackground
|
||||
webView.snp.makeConstraints { make in
|
||||
make.top.equalTo(view.safeAreaLayoutGuide)
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
|
|
@ -81,3 +89,10 @@ extension ModalWebViewController: WKNavigationDelegate {
|
|||
navigationItem.title = webView.title
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIGestureRecognizerDelegate
|
||||
extension ModalWebViewController: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
//
|
||||
// WebViewController.swift
|
||||
// FollowNative
|
||||
//
|
||||
// Created by Innei on 2025/2/27.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SnapKit
|
||||
import UIKit
|
||||
import WebKit
|
||||
|
||||
class WebViewController: UIViewController {
|
||||
private let webView: WKWebView
|
||||
private let url: URL
|
||||
|
||||
init(url: URL) {
|
||||
self.url = url
|
||||
|
||||
let configuration = WKWebViewConfiguration()
|
||||
|
||||
self.webView = WKWebView(frame: .zero, configuration: configuration)
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
webView.navigationDelegate = self
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setupWebView()
|
||||
setupToolbar()
|
||||
loadContent()
|
||||
setupInteractivePopGesture()
|
||||
}
|
||||
|
||||
private func setupInteractivePopGesture() {
|
||||
navigationController?.interactivePopGestureRecognizer?.delegate = self
|
||||
navigationController?.interactivePopGestureRecognizer?.isEnabled = true
|
||||
}
|
||||
|
||||
private func setupWebView() {
|
||||
view.addSubview(webView)
|
||||
view.backgroundColor = .systemBackground
|
||||
webView.snp.makeConstraints { make in
|
||||
make.top.equalTo(view.safeAreaLayoutGuide)
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
private func setupToolbar() {
|
||||
// 确保导航控制器显示工具栏
|
||||
navigationController?.isToolbarHidden = false
|
||||
|
||||
// 创建工具栏按钮
|
||||
let backButton = UIBarButtonItem(
|
||||
image: UIImage(systemName: "chevron.backward"), style: .plain, target: self,
|
||||
action: #selector(goBack))
|
||||
backButton.tintColor = Utils.accentColor
|
||||
|
||||
let forwardButton = UIBarButtonItem(
|
||||
image: UIImage(systemName: "chevron.forward"), style: .plain, target: self,
|
||||
action: #selector(goForward))
|
||||
forwardButton.tintColor = Utils.accentColor
|
||||
|
||||
let refreshButton = UIBarButtonItem(
|
||||
barButtonSystemItem: .refresh, target: self, action: #selector(refreshPage))
|
||||
refreshButton.tintColor = Utils.accentColor
|
||||
|
||||
let safariButton = UIBarButtonItem(
|
||||
image: UIImage(systemName: "safari"), style: .plain, target: self,
|
||||
action: #selector(openInSafari))
|
||||
safariButton.tintColor = Utils.accentColor
|
||||
|
||||
// 添加弹性空间使按钮均匀分布
|
||||
let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
|
||||
|
||||
// 设置工具栏项目
|
||||
toolbarItems = [
|
||||
flexSpace, backButton, flexSpace, forwardButton, flexSpace, refreshButton, flexSpace,
|
||||
safariButton, flexSpace,
|
||||
]
|
||||
}
|
||||
|
||||
private func loadContent() {
|
||||
let request = URLRequest(url: url)
|
||||
webView.load(request)
|
||||
}
|
||||
|
||||
@objc private func openInSafari() {
|
||||
UIApplication.shared.open(url)
|
||||
}
|
||||
|
||||
@objc private func goBack() {
|
||||
if webView.canGoBack {
|
||||
webView.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func goForward() {
|
||||
if webView.canGoForward {
|
||||
webView.goForward()
|
||||
}
|
||||
}
|
||||
|
||||
@objc private func refreshPage() {
|
||||
webView.reload()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - WKNavigationDelegate
|
||||
extension WebViewController: WKNavigationDelegate {
|
||||
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
||||
navigationItem.title = webView.title
|
||||
|
||||
// 更新后退/前进按钮状态
|
||||
updateToolbarButtonsState()
|
||||
}
|
||||
|
||||
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
||||
// 更新后退/前进按钮状态
|
||||
updateToolbarButtonsState()
|
||||
}
|
||||
|
||||
private func updateToolbarButtonsState() {
|
||||
// 找到后退和前进按钮并更新它们的启用状态
|
||||
if let items = toolbarItems {
|
||||
// 后退按钮在索引1
|
||||
if let backButton = items[1] as? UIBarButtonItem {
|
||||
backButton.isEnabled = webView.canGoBack
|
||||
}
|
||||
|
||||
// 前进按钮在索引3
|
||||
if let forwardButton = items[3] as? UIBarButtonItem {
|
||||
forwardButton.isEnabled = webView.canGoForward
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UIGestureRecognizerDelegate
|
||||
extension WebViewController: UIGestureRecognizerDelegate {
|
||||
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
|
@ -16,8 +16,8 @@ public class HelperModule: Module {
|
|||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
guard let rootVC = UIApplication.shared.windows.first?.rootViewController else { return }
|
||||
WebViewManager.presentModalWebView(url: url, from: rootVC)
|
||||
// guard let rootVC = UIApplication.shared.windows.first?.rootViewController else { return }
|
||||
// WebViewManager.pushModalWebView(url: url, from: rootVC)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,11 @@ enum WebViewManager {
|
|||
navController.modalPresentationStyle = .fullScreen
|
||||
viewController.present(navController, animated: true)
|
||||
}
|
||||
|
||||
static func pushModalWebView(url: URL, from navigationController: UINavigationController) {
|
||||
let modalVC = ModalWebViewController(url: url)
|
||||
navigationController.pushViewController(modalVC, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
private class WebViewDelegate: NSObject, WKNavigationDelegate, WKScriptMessageHandler, WKUIDelegate
|
||||
|
|
|
|||
|
|
@ -147,10 +147,12 @@ export const NavigationHeader = ({
|
|||
const setHeaderHeight = useContext(SetNavigationHeaderHeightContext)
|
||||
|
||||
useEffect(() => {
|
||||
const id = scrollY.addListener(({ value }) => {
|
||||
const handler = ({ value }: { value: number }) => {
|
||||
opacityAnimated.value = Math.max(0, Math.min(1, (value + blurThreshold) / 10))
|
||||
})
|
||||
}
|
||||
const id = scrollY.addListener(handler)
|
||||
|
||||
handler({ value: (scrollY as any)._value })
|
||||
return () => {
|
||||
scrollY.removeListener(id)
|
||||
}
|
||||
|
|
@ -191,7 +193,7 @@ export const NavigationHeader = ({
|
|||
}
|
||||
}, [navigation, title])
|
||||
|
||||
const HeaderLeft = headerLeft ?? DefaultHeaderLeft
|
||||
const HeaderLeft = headerLeft ?? DefaultHeaderBackButton
|
||||
|
||||
const renderTitle = customHeaderTitle ?? HeaderTitle
|
||||
const headerTitle =
|
||||
|
|
@ -306,14 +308,27 @@ export const NavigationHeader = ({
|
|||
)
|
||||
}
|
||||
|
||||
const DefaultHeaderLeft = ({ canGoBack }: { canGoBack: boolean }) => {
|
||||
export const DefaultHeaderBackButton = ({ canGoBack }: { canGoBack: boolean }) => {
|
||||
const label = useColor("label")
|
||||
if (!canGoBack) return null
|
||||
return (
|
||||
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
|
||||
<UINavigationHeaderActionButton onPress={() => router.back()}>
|
||||
<MingcuteLeftLineIcon height={20} width={20} color={label} />
|
||||
</TouchableOpacity>
|
||||
</UINavigationHeaderActionButton>
|
||||
)
|
||||
}
|
||||
|
||||
export const UINavigationHeaderActionButton = ({
|
||||
children,
|
||||
onPress,
|
||||
}: {
|
||||
children: ReactNode
|
||||
onPress?: () => void
|
||||
}) => {
|
||||
return (
|
||||
<TouchableOpacity hitSlop={5} className="p-2" onPress={onPress}>
|
||||
{children}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
const Noop = () => null
|
||||
|
|
|
|||
|
|
@ -1,21 +1,19 @@
|
|||
import { useTypeScriptHappyCallback } from "@follow/hooks"
|
||||
import { getDefaultHeaderHeight } from "@react-navigation/elements"
|
||||
import type { NativeStackNavigationOptions } from "@react-navigation/native-stack"
|
||||
import { router, Stack, useNavigation } from "expo-router"
|
||||
import { Stack } from "expo-router"
|
||||
import type { FC, PropsWithChildren } from "react"
|
||||
import { useContext, useEffect, useMemo, useRef, useState } from "react"
|
||||
import type { ScrollView, ScrollViewProps } from "react-native"
|
||||
import { Animated as RNAnimated, TouchableOpacity, useAnimatedValue, View } from "react-native"
|
||||
import { Animated as RNAnimated, useAnimatedValue, View } from "react-native"
|
||||
import type { ReanimatedScrollEvent } from "react-native-reanimated/lib/typescript/hook/commonTypes"
|
||||
import { useSafeAreaFrame, useSafeAreaInsets } from "react-native-safe-area-context"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
|
||||
import {
|
||||
AttachNavigationScrollViewContext,
|
||||
SetAttachNavigationScrollViewContext,
|
||||
} from "@/src/components/layouts/tabbar/contexts/AttachNavigationScrollViewContext"
|
||||
import { useBottomTabBarHeight } from "@/src/components/layouts/tabbar/hooks"
|
||||
import { MingcuteLeftLineIcon } from "@/src/icons/mingcute_left_line"
|
||||
|
||||
import { AnimatedScrollView } from "../../common/AnimatedComponents"
|
||||
import { NavigationHeader } from "../header/NavigationHeader"
|
||||
|
|
@ -104,8 +102,6 @@ export const NavigationBlurEffectHeader = ({
|
|||
headerHideableBottom?: () => React.ReactNode
|
||||
headerTitleAbsolute?: boolean
|
||||
}) => {
|
||||
const canBack = useNavigation().canGoBack()
|
||||
|
||||
const navigationContext = useContext(NavigationContext)!
|
||||
|
||||
const setHeaderHeight = useContext(SetNavigationHeaderHeightContext)
|
||||
|
|
@ -119,7 +115,7 @@ export const NavigationBlurEffectHeader = ({
|
|||
headerTransparent: true,
|
||||
|
||||
headerShown: true,
|
||||
headerLeft: headerLeft ?? (canBack ? () => <NavigationHeaderBackButton /> : undefined),
|
||||
headerLeft,
|
||||
|
||||
header: useTypeScriptHappyCallback(
|
||||
({ options }) => (
|
||||
|
|
@ -147,15 +143,3 @@ export const NavigationBlurEffectHeader = ({
|
|||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export const NavigationHeaderBackButton = () => {
|
||||
return <NavigationHeaderBackButtonImpl />
|
||||
}
|
||||
const NavigationHeaderBackButtonImpl = () => {
|
||||
const label = useColor("label")
|
||||
return (
|
||||
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
|
||||
<MingcuteLeftLineIcon height={20} width={20} color={label} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,13 @@ import Animated, {
|
|||
useSharedValue,
|
||||
withTiming,
|
||||
} from "react-native-reanimated"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
|
||||
import { useUISettingKey } from "@/src/atoms/settings/ui"
|
||||
import { DefaultHeaderBackButton } from "@/src/components/layouts/header/NavigationHeader"
|
||||
import { NavigationContext } from "@/src/components/layouts/views/NavigationContext"
|
||||
import { NavigationBlurEffectHeader } from "@/src/components/layouts/views/SafeNavigationScrollView"
|
||||
import { UserAvatar } from "@/src/components/ui/avatar/UserAvatar"
|
||||
import { FeedIcon } from "@/src/components/ui/icon/feed-icon"
|
||||
import { MingcuteLeftLineIcon } from "@/src/icons/mingcute_left_line"
|
||||
import { apiClient } from "@/src/lib/api-fetch"
|
||||
import { EntryContentContext, useEntryContentContext } from "@/src/modules/entry-content/ctx"
|
||||
import { EntryContentHeaderRightActions } from "@/src/modules/entry-content/EntryContentHeaderRightActions"
|
||||
|
|
@ -197,8 +196,6 @@ interface EntryLeftGroupProps {
|
|||
}
|
||||
|
||||
const EntryLeftGroup = ({ canGoBack, entryId, titleOpacityShareValue }: EntryLeftGroupProps) => {
|
||||
const label = useColor("label")
|
||||
|
||||
const hideRecentReader = useUISettingKey("hideRecentReader")
|
||||
const animatedOpacity = useAnimatedStyle(() => {
|
||||
return {
|
||||
|
|
@ -208,7 +205,7 @@ const EntryLeftGroup = ({ canGoBack, entryId, titleOpacityShareValue }: EntryLef
|
|||
return (
|
||||
<View className="flex-row items-center justify-center">
|
||||
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
|
||||
{canGoBack && <MingcuteLeftLineIcon height={20} width={20} color={label} />}
|
||||
<DefaultHeaderBackButton canGoBack={canGoBack} />
|
||||
</TouchableOpacity>
|
||||
|
||||
{!hideRecentReader && (
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { router } from "expo-router"
|
||||
import { createContext, createElement, useCallback, useContext, useMemo } from "react"
|
||||
import type { ListRenderItem } from "react-native"
|
||||
import { ActivityIndicator, Image, StyleSheet, Text, TouchableOpacity, View } from "react-native"
|
||||
import { ActivityIndicator, Image, StyleSheet, Text, View } from "react-native"
|
||||
import Animated, { LinearTransition } from "react-native-reanimated"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
|
||||
import { Balance } from "@/src/components/common/Balance"
|
||||
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
|
||||
import {
|
||||
NavigationBlurEffectHeader,
|
||||
SafeNavigationScrollView,
|
||||
|
|
@ -99,9 +100,9 @@ export const ListsScreen = () => {
|
|||
const AddListButton = () => {
|
||||
const labelColor = useColor("label")
|
||||
return (
|
||||
<TouchableOpacity hitSlop={10} onPress={() => router.push("/list")}>
|
||||
<UINavigationHeaderActionButton onPress={() => router.push("/list")}>
|
||||
<AddCuteReIcon height={20} width={20} color={labelColor} />
|
||||
</TouchableOpacity>
|
||||
</UINavigationHeaderActionButton>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { createContext, useContext, useEffect, useMemo, useRef, useState } from
|
|||
import { Text, View } from "react-native"
|
||||
|
||||
import { ModalHeaderSubmitButton } from "@/src/components/common/ModalSharedComponents"
|
||||
import { UINavigationHeaderActionButton } from "@/src/components/layouts/header/NavigationHeader"
|
||||
import {
|
||||
NavigationBlurEffectHeader,
|
||||
SafeNavigationScrollView,
|
||||
|
|
@ -47,7 +48,10 @@ export const ManageListScreen = ({
|
|||
const list = useList(id)
|
||||
|
||||
return (
|
||||
<SafeNavigationScrollView className="bg-system-grouped-background mt-6">
|
||||
<SafeNavigationScrollView
|
||||
className="bg-system-grouped-background"
|
||||
contentContainerClassName="mt-6"
|
||||
>
|
||||
<NavigationBlurEffectHeader title={`Manage List - ${list?.title}`} />
|
||||
|
||||
{!!list && <ListImpl id={list.id} />}
|
||||
|
|
@ -86,21 +90,23 @@ const ListImpl: React.FC<{ id: string }> = ({ id }) => {
|
|||
<ManageListContext.Provider value={ctxValue}>
|
||||
<NavigationBlurEffectHeader
|
||||
headerRight={() => (
|
||||
<ModalHeaderSubmitButton
|
||||
isLoading={addFeedsToFeedListMutation.isPending}
|
||||
isValid
|
||||
onPress={() => {
|
||||
addFeedsToFeedListMutation
|
||||
.mutateAsync()
|
||||
.then(() => {
|
||||
router.back()
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(getBizFetchErrorMessage(error))
|
||||
console.error(error)
|
||||
})
|
||||
}}
|
||||
/>
|
||||
<UINavigationHeaderActionButton>
|
||||
<ModalHeaderSubmitButton
|
||||
isLoading={addFeedsToFeedListMutation.isPending}
|
||||
isValid
|
||||
onPress={() => {
|
||||
addFeedsToFeedListMutation
|
||||
.mutateAsync()
|
||||
.then(() => {
|
||||
router.back()
|
||||
})
|
||||
.catch((error) => {
|
||||
toast.error(getBizFetchErrorMessage(error))
|
||||
console.error(error)
|
||||
})
|
||||
}}
|
||||
/>
|
||||
</UINavigationHeaderActionButton>
|
||||
)}
|
||||
/>
|
||||
<GroupedInsetListSectionHeader label="Select feeds to add to the current list" />
|
||||
|
|
|
|||
|
|
@ -1,13 +1,7 @@
|
|||
import { useMutation } from "@tanstack/react-query"
|
||||
import { router } from "expo-router"
|
||||
import { useMemo, useRef } from "react"
|
||||
import {
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
TouchableWithoutFeedback,
|
||||
useAnimatedValue,
|
||||
View,
|
||||
} from "react-native"
|
||||
import { Text, TouchableWithoutFeedback, useAnimatedValue, View } from "react-native"
|
||||
import { KeyboardController } from "react-native-keyboard-controller"
|
||||
import type { OtpInputRef } from "react-native-otp-entry"
|
||||
import { OtpInput } from "react-native-otp-entry"
|
||||
|
|
@ -15,7 +9,6 @@ import { useColor } from "react-native-uikit-colors"
|
|||
|
||||
import { NavigationContext } from "@/src/components/layouts/views/NavigationContext"
|
||||
import { NavigationBlurEffectHeader } from "@/src/components/layouts/views/SafeNavigationScrollView"
|
||||
import { MingcuteLeftLineIcon } from "@/src/icons/mingcute_left_line"
|
||||
import { twoFactor } from "@/src/lib/auth"
|
||||
import { queryClient } from "@/src/lib/query-client"
|
||||
import { toast } from "@/src/lib/toast"
|
||||
|
|
@ -55,18 +48,7 @@ export default function TwoFactorAuthScreen() {
|
|||
return (
|
||||
<NavigationContext.Provider value={useMemo(() => ({ scrollY }), [scrollY])}>
|
||||
<View className="flex-1 p-safe">
|
||||
<NavigationBlurEffectHeader
|
||||
headerShown
|
||||
headerTitle=""
|
||||
title="2FA"
|
||||
headerLeft={() => {
|
||||
return (
|
||||
<TouchableOpacity onPress={() => router.back()}>
|
||||
<MingcuteLeftLineIcon color={label} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<NavigationBlurEffectHeader headerShown headerTitle="" title="2FA" />
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() => {
|
||||
KeyboardController.dismiss()
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
import { router, Stack, useNavigation } from "expo-router"
|
||||
import { TouchableOpacity, View } from "react-native"
|
||||
import { useColor } from "react-native-uikit-colors"
|
||||
import { getDefaultHeaderHeight } from "@react-navigation/elements"
|
||||
import { useMemo } from "react"
|
||||
import { useAnimatedValue, View } from "react-native"
|
||||
import { useSafeAreaFrame, useSafeAreaInsets } from "react-native-safe-area-context"
|
||||
|
||||
import { NavigationContext } from "@/src/components/layouts/views/NavigationContext"
|
||||
import { NavigationBlurEffectHeader } from "@/src/components/layouts/views/SafeNavigationScrollView"
|
||||
import { Markdown } from "@/src/components/ui/typography/Markdown"
|
||||
import { MingcuteLeftLineIcon } from "@/src/icons/mingcute_left_line"
|
||||
|
||||
const txt = `# Terms of Service
|
||||
|
||||
|
|
@ -93,26 +95,18 @@ export const TermsMarkdown = () => {
|
|||
}
|
||||
|
||||
export default function Teams() {
|
||||
const canGoBack = useNavigation().canGoBack()
|
||||
const label = useColor("label")
|
||||
const scrollY = useAnimatedValue(100)
|
||||
const insets = useSafeAreaInsets()
|
||||
const frame = useSafeAreaFrame()
|
||||
const headerHeight = getDefaultHeaderHeight(frame, false, insets.top)
|
||||
return (
|
||||
<View className="flex-1">
|
||||
<Stack.Screen
|
||||
options={{
|
||||
headerBackTitle: "Login",
|
||||
headerTitle: "Terms of Service",
|
||||
headerShown: true,
|
||||
headerLeft: canGoBack
|
||||
? () => (
|
||||
<TouchableOpacity hitSlop={10} onPress={() => router.back()}>
|
||||
<MingcuteLeftLineIcon height={20} width={20} color={label} />
|
||||
</TouchableOpacity>
|
||||
)
|
||||
: undefined,
|
||||
}}
|
||||
/>
|
||||
<NavigationContext.Provider value={useMemo(() => ({ scrollY }), [scrollY])}>
|
||||
<View className="flex-1">
|
||||
<NavigationBlurEffectHeader headerShown title="Terms of Service" />
|
||||
|
||||
<TermsMarkdown />
|
||||
</View>
|
||||
<View style={{ height: headerHeight }} />
|
||||
<TermsMarkdown />
|
||||
</View>
|
||||
</NavigationContext.Provider>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue