Skip to content

Commit

Permalink
feat(rn-modal): apply modal header blur effect
Browse files Browse the repository at this point in the history
Signed-off-by: Innei <[email protected]>
  • Loading branch information
Innei committed Jan 23, 2025
1 parent b0012c1 commit ccd1978
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 22 deletions.
28 changes: 28 additions & 0 deletions apps/mobile/src/components/common/SafeModalScrollView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @description only for iOS modal
*
* ```
* Set screen options:
* + headerTransparent: true,
* + headerBackground: BlurEffectWithBottomBorder,
* ```
*/
import { useHeaderHeight } from "@react-navigation/elements"
import type { KeyboardAwareScrollViewProps } from "react-native-keyboard-controller"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
import { useSafeAreaInsets } from "react-native-safe-area-context"

interface SafeModalScrollViewProps extends KeyboardAwareScrollViewProps {}
export const SafeModalScrollView = (props: SafeModalScrollViewProps) => {
const headerHeight = useHeaderHeight()
const insets = useSafeAreaInsets()
return (
<KeyboardAwareScrollView
{...props}
scrollIndicatorInsets={{ top: headerHeight, bottom: insets.bottom }}
contentContainerStyle={{ paddingTop: headerHeight, paddingBottom: insets.bottom }}
>
{props.children}
</KeyboardAwareScrollView>
)
}
2 changes: 1 addition & 1 deletion apps/mobile/src/components/common/SwipeableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ export const SwipeableItem: React.FC<SwipeableItemProps> = ({
style={[
styles.absoluteFill,
{
backgroundColor: rightActions?.[0]?.backgroundColor ?? "#fff",
backgroundColor: rightActions?.at(-1)?.backgroundColor ?? "#fff",
},
]}
/>
Expand Down
24 changes: 17 additions & 7 deletions apps/mobile/src/components/ui/pressable/item-pressable.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { composeEventHandlers } from "@follow/utils"
import { memo, useEffect, useState } from "react"
import { useTypeScriptHappyCallback } from "@follow/hooks"
import { cn, composeEventHandlers } from "@follow/utils"
import { Fragment, memo, useEffect, useState } from "react"
import type { Pressable } from "react-native"
import { StyleSheet } from "react-native"
import {
import Animated, {
Easing,
interpolateColor,
useAnimatedStyle,
Expand Down Expand Up @@ -49,10 +49,20 @@ export const ItemPressable: typeof Pressable = memo(({ children, ...props }) =>
onPressOut={composeEventHandlers(props.onPressOut, () => setIsPressing(false))}
onHoverIn={composeEventHandlers(props.onHoverIn, () => setIsPressing(true))}
onHoverOut={composeEventHandlers(props.onHoverOut, () => setIsPressing(false))}
className={props.className}
style={StyleSheet.flatten([colorStyle, props.style])}
className={cn(props.className, "bg-secondary-system-background relative")}
style={props.style}
>
{children}
{useTypeScriptHappyCallback(
(props) => {
return (
<Fragment>
<Animated.View className="absolute inset-0" style={colorStyle} />
{typeof children === "function" ? children(props) : children}
</Fragment>
)
},
[children, colorStyle],
)}
</ReAnimatedPressable>
)
})
15 changes: 13 additions & 2 deletions apps/mobile/src/modules/settings/routes/Lists.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
} from "@/src/components/ui/grouped/GroupedList"
import { FallbackIcon } from "@/src/components/ui/icon/fallback-icon"
import { LoadingIndicator } from "@/src/components/ui/loading"
import { ItemPressable } from "@/src/components/ui/pressable/item-pressable"
import { views } from "@/src/constants/views"
import { AddCuteReIcon } from "@/src/icons/add_cute_re"
import { PowerIcon } from "@/src/icons/power"
Expand Down Expand Up @@ -124,6 +125,13 @@ const ListItemCellImpl: ListRenderItem<ListModel> = ({ item: list }) => {
return (
<SwipeableItem
rightActions={[
{
label: "Manage",
onPress: () => {
router.push(`/manage-list?id=${list.id}`)
},
backgroundColor: accentColor,
},
{
label: "Edit",
onPress: () => {
Expand All @@ -133,7 +141,10 @@ const ListItemCellImpl: ListRenderItem<ListModel> = ({ item: list }) => {
},
]}
>
<View className="bg-secondary-system-grouped-background flex-row p-4">
<ItemPressable
className="flex-row p-4"
onPress={() => router.push(`/manage-list?id=${list.id}`)}
>
<View className="size-16 overflow-hidden rounded-lg">
{list.image ? (
<Image source={{ uri: list.image }} resizeMode="cover" className="size-full" />
Expand Down Expand Up @@ -189,7 +200,7 @@ const ListItemCellImpl: ListRenderItem<ListModel> = ({ item: list }) => {
</View>
)}
</View>
</View>
</ItemPressable>
</SwipeableItem>
)
}
Expand Down
6 changes: 6 additions & 0 deletions apps/mobile/src/screens/(modal)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ export default function ModalLayout() {
title: "List",
}}
/>
<Stack.Screen
name="manage-list"
options={{
title: "Manage List",
}}
/>
</Stack>
)
}
10 changes: 6 additions & 4 deletions apps/mobile/src/screens/(modal)/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { router, Stack, useLocalSearchParams } from "expo-router"
import { memo, useState } from "react"
import { Controller, useForm } from "react-hook-form"
import { View } from "react-native"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
import { z } from "zod"

import { BlurEffectWithBottomBorder } from "@/src/components/common/BlurEffect"
import {
ModalHeaderCloseButton,
ModalHeaderSubmitButton,
} from "@/src/components/common/ModalSharedComponents"
import { SafeModalScrollView } from "@/src/components/common/SafeModalScrollView"
import { FormProvider, useFormContext } from "@/src/components/ui/form/FormProvider"
import { FormLabel } from "@/src/components/ui/form/Label"
import { NumberField, TextField } from "@/src/components/ui/form/TextField"
Expand Down Expand Up @@ -65,7 +66,7 @@ export default function ListScreen() {

return (
<FormProvider form={form}>
<KeyboardAwareScrollView className="bg-system-grouped-background flex-1 pb-safe">
<SafeModalScrollView className="bg-system-grouped-background flex-1 pb-safe">
<ScreenOptions title={list?.title} listId={listId} />

<GroupedInsetListCard showSeparator={false} className="mt-6 px-3 py-6">
Expand Down Expand Up @@ -186,7 +187,7 @@ export default function ListScreen() {
/>
</GroupedInsetListCard>
)}
</KeyboardAwareScrollView>
</SafeModalScrollView>
</FormProvider>
)
}
Expand All @@ -208,7 +209,8 @@ const ScreenOptions = memo(({ title, listId }: ScreenOptionsProps) => {
options={{
headerLeft: ModalHeaderCloseButton,
gestureEnabled: !isDirty,

headerTransparent: true,
headerBackground: BlurEffectWithBottomBorder,
headerRight: () => (
<FormProvider form={form}>
<ModalHeaderSubmitButton
Expand Down
5 changes: 5 additions & 0 deletions apps/mobile/src/screens/(modal)/manage-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { View } from "react-native"

export default function ManageListScreen() {
return <View />
}
14 changes: 6 additions & 8 deletions apps/mobile/src/screens/(modal)/rsshub-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import { router, Stack, useLocalSearchParams } from "expo-router"
import { memo, useEffect, useMemo, useState } from "react"
import { Controller, useForm } from "react-hook-form"
import { Linking, Text, TouchableOpacity, View } from "react-native"
import { KeyboardAwareScrollView } from "react-native-keyboard-controller"
import { useSafeAreaInsets } from "react-native-safe-area-context"
import { z } from "zod"

import { BlurEffectWithBottomBorder } from "@/src/components/common/BlurEffect"
import { HeaderTitleExtra } from "@/src/components/common/HeaderTitleExtra"
import {
ModalHeaderCloseButton,
ModalHeaderSubmitButton,
} from "@/src/components/common/ModalSharedComponents"
import { SafeModalScrollView } from "@/src/components/common/SafeModalScrollView"
import { FormProvider, useFormContext } from "@/src/components/ui/form/FormProvider"
import { Select } from "@/src/components/ui/form/Select"
import { TextField } from "@/src/components/ui/form/TextField"
Expand Down Expand Up @@ -111,7 +111,6 @@ function FormImpl({ route, routePrefix, name }: RsshubFormParams) {
mode: "all",
})

const insets = useSafeAreaInsets()
return (
<FormProvider form={form}>
<ScreenOptions
Expand All @@ -122,10 +121,7 @@ function FormImpl({ route, routePrefix, name }: RsshubFormParams) {
/>

<PortalProvider>
<KeyboardAwareScrollView
className="bg-system-grouped-background"
contentContainerStyle={{ paddingBottom: insets.bottom, flexGrow: 1 }}
>
<SafeModalScrollView className="bg-system-grouped-background">
<View className="bg-secondary-system-grouped-background mx-2 mt-2 gap-4 rounded-lg px-3 py-6">
{keys.map((keyItem) => {
const parameters = normalizeRSSHubParameters(route.parameters[keyItem.name]!)
Expand Down Expand Up @@ -198,7 +194,7 @@ function FormImpl({ route, routePrefix, name }: RsshubFormParams) {
/>
</View>
)}
</KeyboardAwareScrollView>
</SafeModalScrollView>
</PortalProvider>
</FormProvider>
)
Expand Down Expand Up @@ -244,6 +240,8 @@ const ScreenOptions = memo(({ name, routeName, route, routePrefix }: ScreenOptio
options={{
headerLeft: ModalHeaderCloseButton,
gestureEnabled: !form.formState.isDirty,
headerBackground: BlurEffectWithBottomBorder,
headerTransparent: true,

headerRight: () => (
<FormProvider form={form}>
Expand Down

0 comments on commit ccd1978

Please sign in to comment.