This commit is contained in:
Fredrik Burmester
2025-09-30 11:58:59 +02:00
parent 47c52e0739
commit 7a11f4a54b
17 changed files with 580 additions and 306 deletions

View File

@@ -3,7 +3,7 @@ import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View } from "react-native";
import { Text } from "./common/Text";
import { type OptionGroup, PlatformOptionsMenu } from "./PlatformOptionsMenu";
import { type OptionGroup, PlatformDropdown } from "./PlatformDropdown";
interface Props extends React.ComponentProps<typeof View> {
source?: MediaSourceInfo;
@@ -34,32 +34,25 @@ export const AudioTrackSelector: React.FC<Props> = ({
const optionGroups: OptionGroup[] = useMemo(
() => [
{
id: "audio-streams",
title: "Audio streams",
options:
audioStreams?.map((audio, idx) => ({
id: `${audio.Index || idx}`,
type: "radio" as const,
groupId: "audio-streams",
label: audio.DisplayTitle || `Audio Stream ${idx + 1}`,
value: audio.Index ?? idx,
selected: audio.Index === selected,
onPress: () => {
if (audio.Index !== null && audio.Index !== undefined) {
onChange(audio.Index);
}
},
})) || [],
},
],
[audioStreams, selected],
[audioStreams, selected, onChange],
);
const handleOptionSelect = (optionId: string) => {
const selectedStream = audioStreams?.find(
(audio, idx) => `${audio.Index || idx}` === optionId,
);
if (
selectedStream &&
selectedStream.Index !== null &&
selectedStream.Index !== undefined
) {
onChange(selectedStream.Index);
}
const handleOptionSelect = () => {
setOpen(false);
};
@@ -84,7 +77,7 @@ export const AudioTrackSelector: React.FC<Props> = ({
minWidth: 50,
}}
>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
title={t("item_card.audio")}

View File

@@ -2,7 +2,7 @@ import { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View } from "react-native";
import { Text } from "./common/Text";
import { type OptionGroup, PlatformOptionsMenu } from "./PlatformOptionsMenu";
import { type OptionGroup, PlatformDropdown } from "./PlatformDropdown";
export type Bitrate = {
key: string;
@@ -125,7 +125,7 @@ export const BitrateSelector: React.FC<Props> = ({
maxWidth: 200,
}}
>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
title={t("item_card.quality")}

View File

@@ -6,7 +6,7 @@ import { useCallback, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View } from "react-native";
import { Text } from "./common/Text";
import { type OptionGroup, PlatformOptionsMenu } from "./PlatformOptionsMenu";
import { type OptionGroup, PlatformDropdown } from "./PlatformDropdown";
interface Props extends React.ComponentProps<typeof View> {
item: BaseItemDto;
@@ -93,7 +93,7 @@ export const MediaSourceSelector: React.FC<Props> = ({
minWidth: 50,
}}
>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
title={t("item_card.video")}

View File

@@ -0,0 +1,299 @@
import { Button, ContextMenu, Host, Picker } from "@expo/ui/swift-ui";
import { Ionicons } from "@expo/vector-icons";
import { useEffect } from "react";
import { Platform, StyleSheet, TouchableOpacity, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Text } from "@/components/common/Text";
import { useGlobalModal } from "@/providers/GlobalModalProvider";
// Option types
export type RadioOption<T = any> = {
type: "radio";
label: string;
value: T;
selected: boolean;
onPress: () => void;
disabled?: boolean;
};
export type ToggleOption = {
type: "toggle";
label: string;
value: boolean;
onToggle: () => void;
disabled?: boolean;
};
export type Option = RadioOption | ToggleOption;
// Option group structure
export type OptionGroup = {
title?: string;
options: Option[];
};
interface PlatformDropdownProps {
trigger?: React.ReactNode;
title?: string;
groups: OptionGroup[];
open?: boolean;
onOpenChange?: (open: boolean) => void;
onOptionSelect?: (value?: any) => void;
expoUIConfig?: {
hostStyle?: any;
};
bottomSheetConfig?: {
enableDynamicSizing?: boolean;
enablePanDownToClose?: boolean;
};
}
const ToggleSwitch: React.FC<{ value: boolean }> = ({ value }) => (
<View
className={`w-12 h-7 rounded-full ${value ? "bg-purple-600" : "bg-neutral-600"} flex-row items-center`}
>
<View
className={`w-5 h-5 rounded-full bg-white shadow-md transform transition-transform ${
value ? "translate-x-6" : "translate-x-1"
}`}
/>
</View>
);
const OptionItem: React.FC<{ option: Option; isLast?: boolean }> = ({
option,
isLast,
}) => {
const isToggle = option.type === "toggle";
const handlePress = isToggle ? option.onToggle : option.onPress;
return (
<>
<TouchableOpacity
onPress={handlePress}
disabled={option.disabled}
className={`px-4 py-3 flex flex-row items-center justify-between ${
option.disabled ? "opacity-50" : ""
}`}
>
<Text className='flex-1 text-white'>{option.label}</Text>
{isToggle ? (
<ToggleSwitch value={option.value} />
) : option.selected ? (
<Ionicons name='checkmark-circle' size={24} color='#9333ea' />
) : (
<Ionicons name='ellipse-outline' size={24} color='#6b7280' />
)}
</TouchableOpacity>
{!isLast && (
<View
style={{
height: StyleSheet.hairlineWidth,
}}
className='bg-neutral-700 mx-4'
/>
)}
</>
);
};
const OptionGroupComponent: React.FC<{ group: OptionGroup }> = ({ group }) => (
<View className='mb-6'>
{group.title && (
<Text className='text-lg font-semibold mb-3 text-neutral-300'>
{group.title}
</Text>
)}
<View
style={{
borderRadius: 12,
overflow: "hidden",
}}
className='bg-neutral-800 rounded-xl overflow-hidden'
>
{group.options.map((option, index) => (
<OptionItem
key={index}
option={option}
isLast={index === group.options.length - 1}
/>
))}
</View>
</View>
);
const BottomSheetContent: React.FC<{
title?: string;
groups: OptionGroup[];
onOptionSelect?: (value?: any) => void;
}> = ({ title, groups, onOptionSelect }) => {
const insets = useSafeAreaInsets();
// Wrap the groups to call onOptionSelect when an option is pressed
const wrappedGroups = groups.map((group) => ({
...group,
options: group.options.map((option) => {
if (option.type === "radio") {
return {
...option,
onPress: () => {
option.onPress();
onOptionSelect?.(option.value);
},
};
}
if (option.type === "toggle") {
return {
...option,
onToggle: () => {
option.onToggle();
onOptionSelect?.(option.value);
},
};
}
return option;
}),
}));
return (
<View
className='px-4 pb-8 pt-2'
style={{
paddingLeft: Math.max(16, insets.left),
paddingRight: Math.max(16, insets.right),
}}
>
{title && <Text className='font-bold text-2xl mb-6'>{title}</Text>}
{wrappedGroups.map((group, index) => (
<OptionGroupComponent key={index} group={group} />
))}
</View>
);
};
export function PlatformDropdown({
trigger,
title,
groups,
open,
onOpenChange,
onOptionSelect,
expoUIConfig,
bottomSheetConfig,
}: PlatformDropdownProps) {
const { showModal, hideModal } = useGlobalModal();
const handlePress = () => {
if (Platform.OS === "android") {
onOpenChange?.(true);
showModal(
<BottomSheetContent
title={title}
groups={groups}
onOptionSelect={onOptionSelect}
/>,
{
enableDynamicSizing: bottomSheetConfig?.enableDynamicSizing ?? true,
enablePanDownToClose: bottomSheetConfig?.enablePanDownToClose ?? true,
},
);
}
};
// Close modal when open prop changes to false
useEffect(() => {
if (Platform.OS === "android" && open === false) {
hideModal();
}
}, [open, hideModal]);
if (Platform.OS === "ios") {
console.log("[PlatformDropdown iOS] Rendering with groups:", groups.length);
return (
<Host style={expoUIConfig?.hostStyle}>
<ContextMenu>
<ContextMenu.Trigger>
<View className='w-9 h-9 flex items-center justify-center'>
{trigger || <Button variant='bordered'>Show Menu</Button>}
</View>
</ContextMenu.Trigger>
<ContextMenu.Items>
{groups.flatMap((group, groupIndex) => {
// Check if this group has radio options
const radioOptions = group.options.filter(
(opt) => opt.type === "radio",
) as RadioOption[];
const toggleOptions = group.options.filter(
(opt) => opt.type === "toggle",
) as ToggleOption[];
console.log(
`[PlatformDropdown iOS] Group ${groupIndex}: ${radioOptions.length} radio, ${toggleOptions.length} toggle`,
);
const items = [];
// Add Picker for radio options if present
if (radioOptions.length > 0) {
items.push(
<Picker
key={`picker-${groupIndex}`}
label={group.title || "Options"}
options={radioOptions.map((opt) => opt.label)}
variant='menu'
selectedIndex={radioOptions.findIndex(
(opt) => opt.selected,
)}
onOptionSelected={(event: any) => {
console.log(
"[PlatformDropdown iOS] Picker option selected:",
event.nativeEvent.index,
);
const index = event.nativeEvent.index;
const selectedOption = radioOptions[index];
selectedOption?.onPress();
onOptionSelect?.(selectedOption?.value);
}}
/>,
);
}
// Add Buttons for toggle options
toggleOptions.forEach((option, optionIndex) => {
items.push(
<Button
key={`toggle-${groupIndex}-${optionIndex}`}
systemImage={
option.value ? "checkmark.circle.fill" : "circle"
}
onPress={() => {
console.log(
"[PlatformDropdown iOS] Toggle pressed:",
option.label,
);
option.onToggle();
onOptionSelect?.(option.value);
}}
disabled={option.disabled}
>
{option.label}
</Button>,
);
});
return items;
})}
</ContextMenu.Items>
</ContextMenu>
</Host>
);
}
// Android: Trigger button for bottom modal
return (
<TouchableOpacity onPress={handlePress}>
{trigger || <Text className='text-white'>Open Menu</Text>}
</TouchableOpacity>
);
}

View File

@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View } from "react-native";
import { tc } from "@/utils/textTools";
import { Text } from "./common/Text";
import { type OptionGroup, PlatformOptionsMenu } from "./PlatformOptionsMenu";
import { type OptionGroup, PlatformDropdown } from "./PlatformDropdown";
interface Props extends React.ComponentProps<typeof View> {
source?: MediaSourceInfo;
@@ -103,7 +103,7 @@ export const SubtitleTrackSelector: React.FC<Props> = ({
maxWidth: 200,
}}
>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
title={t("item_card.subtitles")}

View File

@@ -8,7 +8,7 @@ import {
import { Platform, TouchableOpacity, View, type ViewProps } from "react-native";
import { Text } from "@/components/common/Text";
import DisabledSetting from "@/components/settings/DisabledSetting";
import { type OptionGroup, PlatformOptionsMenu } from "../PlatformOptionsMenu";
import { type OptionGroup, PlatformDropdown } from "../PlatformDropdown";
interface Props<T> {
data: T[];
@@ -44,29 +44,6 @@ const Dropdown = <T,>({
}
}, [selected, onSelected]);
const optionGroups: OptionGroup[] = useMemo(
() => [
{
id: "dropdown-items",
title: label,
options: data.map((item) => {
const key = keyExtractor(item);
const isSelected =
selected?.some((s) => keyExtractor(s) === key) || false;
return {
id: key,
type: multiple ? "checkbox" : ("radio" as const),
groupId: "dropdown-items",
label: titleExtractor(item) || key,
...(multiple ? { checked: isSelected } : { selected: isSelected }),
};
}),
},
],
[data, selected, multiple, keyExtractor, titleExtractor, label],
);
const handleOptionSelect = (optionId: string, value?: any) => {
const selectedItem = data.find((item) => keyExtractor(item) === optionId);
if (!selectedItem) return;
@@ -91,6 +68,45 @@ const Dropdown = <T,>({
}
};
const optionGroups: OptionGroup[] = useMemo(
() => [
{
title: label,
options: data.map((item) => {
const key = keyExtractor(item);
const isSelected =
selected?.some((s) => keyExtractor(s) === key) || false;
if (multiple) {
return {
type: "toggle" as const,
label: titleExtractor(item) || key,
value: isSelected,
onToggle: () => handleOptionSelect(key, !isSelected),
};
}
return {
type: "radio" as const,
label: titleExtractor(item) || key,
value: key,
selected: isSelected,
onPress: () => handleOptionSelect(key),
};
}),
},
],
[
data,
selected,
multiple,
keyExtractor,
titleExtractor,
label,
handleOptionSelect,
],
);
const getDisplayValue = () => {
if (selected?.length !== undefined && selected.length > 0) {
return selected.map(titleExtractor).join(",");
@@ -120,7 +136,7 @@ const Dropdown = <T,>({
return (
<DisabledSetting disabled={disabled === true} showText={false} {...props}>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
title={label}

View File

@@ -1,9 +1,9 @@
import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { t } from "i18next";
import { useEffect, useMemo, useState } from "react";
import { Platform, TouchableOpacity, View } from "react-native";
import { useEffect, useMemo } from "react";
import { Platform, View } from "react-native";
import { Text } from "../common/Text";
import { type OptionGroup, PlatformOptionsMenu } from "../PlatformOptionsMenu";
import { PlatformDropdown } from "../PlatformDropdown";
type Props = {
item: BaseItemDto;
@@ -31,7 +31,6 @@ export const SeasonDropdown: React.FC<Props> = ({
onSelect,
}) => {
const isTv = Platform.isTV;
const [open, setOpen] = useState(false);
const keys = useMemo<SeasonKeys>(
() =>
@@ -57,10 +56,9 @@ export const SeasonDropdown: React.FC<Props> = ({
const sortByIndex = (a: BaseItemDto, b: BaseItemDto) =>
Number(a[keys.index]) - Number(b[keys.index]);
const optionGroups: OptionGroup[] = useMemo(
const optionGroups = useMemo(
() => [
{
id: "seasons",
title: t("item_card.seasons"),
options:
seasons?.sort(sortByIndex).map((season: any) => {
@@ -69,28 +67,18 @@ export const SeasonDropdown: React.FC<Props> = ({
season.Name ||
`Season ${season.IndexNumber}`;
return {
id: `${season.Id || season.IndexNumber}`,
type: "radio" as const,
groupId: "seasons",
label: title,
value: season.Id || season.IndexNumber,
selected: Number(season[keys.index]) === Number(seasonIndex),
onPress: () => onSelect(season),
};
}) || [],
},
],
[seasons, keys, seasonIndex],
[seasons, keys, seasonIndex, onSelect],
);
const handleSeasonSelect = (optionId: string) => {
const selectedSeason = seasons?.find(
(season: any) => `${season.Id || season.IndexNumber}` === optionId,
);
if (selectedSeason) {
onSelect(selectedSeason);
}
setOpen(false);
};
useEffect(() => {
if (isTv) return;
if (seasons && seasons.length > 0 && seasonIndex === undefined) {
@@ -132,36 +120,19 @@ export const SeasonDropdown: React.FC<Props> = ({
keys,
]);
const trigger = (
<View className='flex flex-row'>
<TouchableOpacity
className='bg-neutral-900 rounded-2xl border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between'
onPress={() => setOpen(true)}
>
<Text>
{t("item_card.season")} {seasonIndex}
</Text>
</TouchableOpacity>
</View>
);
if (isTv) return null;
return (
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
trigger={
<View className='bg-neutral-900 rounded-2xl border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between'>
<Text>
{t("item_card.season")} {seasonIndex}
</Text>
</View>
}
title={t("item_card.seasons")}
open={open}
onOpenChange={setOpen}
onOptionSelect={handleSeasonSelect}
expoUIConfig={{
hostStyle: { flex: 1 },
}}
bottomSheetConfig={{
enableDynamicSizing: true,
enablePanDownToClose: true,
}}
/>
);
};

View File

@@ -1,12 +1,12 @@
import { useMemo, useState } from "react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View, type ViewProps } from "react-native";
import { Platform, View, type ViewProps } from "react-native";
import { APP_LANGUAGES } from "@/i18n";
import { useSettings } from "@/utils/atoms/settings";
import { Text } from "../common/Text";
import { ListGroup } from "../list/ListGroup";
import { ListItem } from "../list/ListItem";
import { type OptionGroup, PlatformOptionsMenu } from "../PlatformOptionsMenu";
import { PlatformDropdown } from "../PlatformDropdown";
interface Props extends ViewProps {}
@@ -14,55 +14,32 @@ export const AppLanguageSelector: React.FC<Props> = () => {
const isTv = Platform.isTV;
const { settings, updateSettings } = useSettings();
const { t } = useTranslation();
const [open, setOpen] = useState(false);
const optionGroups: OptionGroup[] = useMemo(() => {
const optionGroups = useMemo(() => {
const options = [
{
id: "system",
type: "radio" as const,
groupId: "languages",
label: t("home.settings.languages.system"),
value: "system",
selected: !settings?.preferedLanguage,
onPress: () => updateSettings({ preferedLanguage: undefined }),
},
...APP_LANGUAGES.map((lang) => ({
id: lang.value,
type: "radio" as const,
groupId: "languages",
label: lang.label,
value: lang.value,
selected: lang.value === settings?.preferedLanguage,
onPress: () => updateSettings({ preferedLanguage: lang.value }),
})),
];
return [
{
id: "languages",
title: t("home.settings.languages.title"),
options,
},
];
}, [settings?.preferedLanguage, t]);
const handleOptionSelect = (optionId: string) => {
if (optionId === "system") {
updateSettings({ preferedLanguage: undefined });
} else {
updateSettings({ preferedLanguage: optionId });
}
setOpen(false);
};
const trigger = (
<TouchableOpacity
className='bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between'
onPress={() => setOpen(true)}
>
<Text>
{APP_LANGUAGES.find((l) => l.value === settings?.preferedLanguage)
?.label || t("home.settings.languages.system")}
</Text>
</TouchableOpacity>
);
}, [settings?.preferedLanguage, t, updateSettings]);
if (isTv) return null;
if (!settings) return null;
@@ -71,20 +48,18 @@ export const AppLanguageSelector: React.FC<Props> = () => {
<View>
<ListGroup title={t("home.settings.languages.title")}>
<ListItem title={t("home.settings.languages.app_language")}>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
trigger={
<View className='bg-neutral-800 rounded-lg border-neutral-900 border px-3 py-2 flex flex-row items-center justify-between'>
<Text>
{APP_LANGUAGES.find(
(l) => l.value === settings?.preferedLanguage,
)?.label || t("home.settings.languages.system")}
</Text>
</View>
}
title={t("home.settings.languages.title")}
open={open}
onOpenChange={setOpen}
onOptionSelect={handleOptionSelect}
expoUIConfig={{
hostStyle: { flex: 1 },
}}
bottomSheetConfig={{
enableDynamicSizing: true,
enablePanDownToClose: true,
}}
/>
</ListItem>
</ListGroup>

View File

@@ -1,20 +1,19 @@
import { Ionicons } from "@expo/vector-icons";
import { useMemo, useState } from "react";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { Platform, TouchableOpacity, View, type ViewProps } from "react-native";
import { Platform, View, type ViewProps } from "react-native";
import { Switch } from "react-native-gesture-handler";
import { useSettings } from "@/utils/atoms/settings";
import { Text } from "../common/Text";
import { ListGroup } from "../list/ListGroup";
import { ListItem } from "../list/ListItem";
import { type OptionGroup, PlatformOptionsMenu } from "../PlatformOptionsMenu";
import { PlatformDropdown } from "../PlatformDropdown";
import { useMedia } from "./MediaContext";
interface Props extends ViewProps {}
export const AudioToggles: React.FC<Props> = ({ ...props }) => {
const isTv = Platform.isTV;
const [open, setOpen] = useState(false);
const media = useMedia();
const { pluginSettings } = useSettings();
@@ -22,69 +21,39 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
const cultures = media.cultures;
const { t } = useTranslation();
const optionGroups: OptionGroup[] = useMemo(() => {
const optionGroups = useMemo(() => {
const options = [
{
id: "none",
type: "radio" as const,
groupId: "audio-languages",
label: t("home.settings.audio.none"),
value: "none",
selected: !settings?.defaultAudioLanguage,
onPress: () => updateSettings({ defaultAudioLanguage: null }),
},
...(cultures?.map((culture) => ({
id:
culture.ThreeLetterISOLanguageName ||
culture.DisplayName ||
"unknown",
type: "radio" as const,
groupId: "audio-languages",
label:
culture.DisplayName ||
culture.ThreeLetterISOLanguageName ||
"Unknown",
value:
culture.ThreeLetterISOLanguageName ||
culture.DisplayName ||
"unknown",
selected:
culture.ThreeLetterISOLanguageName ===
settings?.defaultAudioLanguage?.ThreeLetterISOLanguageName,
onPress: () => updateSettings({ defaultAudioLanguage: culture }),
})) || []),
];
return [
{
id: "audio-languages",
title: t("home.settings.audio.language"),
options,
},
];
}, [cultures, settings?.defaultAudioLanguage, t]);
const handleOptionSelect = (optionId: string) => {
if (optionId === "none") {
updateSettings({ defaultAudioLanguage: null });
} else {
const selectedCulture = cultures?.find(
(culture) =>
(culture.ThreeLetterISOLanguageName || culture.DisplayName) ===
optionId,
);
if (selectedCulture) {
updateSettings({ defaultAudioLanguage: selectedCulture });
}
}
setOpen(false);
};
const trigger = (
<TouchableOpacity
className='flex flex-row items-center justify-between py-3 pl-3'
onPress={() => setOpen(true)}
>
<Text className='mr-1 text-[#8E8D91]'>
{settings?.defaultAudioLanguage?.DisplayName ||
t("home.settings.audio.none")}
</Text>
<Ionicons name='chevron-expand-sharp' size={18} color='#5A5960' />
</TouchableOpacity>
);
}, [cultures, settings?.defaultAudioLanguage, t, updateSettings]);
if (isTv) return null;
if (!settings) return null;
@@ -112,20 +81,22 @@ export const AudioToggles: React.FC<Props> = ({ ...props }) => {
/>
</ListItem>
<ListItem title={t("home.settings.audio.audio_language")}>
<PlatformOptionsMenu
<PlatformDropdown
groups={optionGroups}
trigger={trigger}
trigger={
<View className='flex flex-row items-center justify-between py-3 pl-3'>
<Text className='mr-1 text-[#8E8D91]'>
{settings?.defaultAudioLanguage?.DisplayName ||
t("home.settings.audio.none")}
</Text>
<Ionicons
name='chevron-expand-sharp'
size={18}
color='#5A5960'
/>
</View>
}
title={t("home.settings.audio.language")}
open={open}
onOpenChange={setOpen}
onOptionSelect={handleOptionSelect}
expoUIConfig={{
hostStyle: { flex: 1 },
}}
bottomSheetConfig={{
enableDynamicSizing: true,
enablePanDownToClose: true,
}}
/>
</ListItem>
</ListGroup>

View File

@@ -1,5 +1,6 @@
import type { ParamListBase, RouteProp } from "@react-navigation/native";
import type { NativeStackNavigationOptions } from "@react-navigation/native-stack";
import { Platform } from "react-native";
import { HeaderBackButton } from "../common/HeaderBackButton";
type ICommonScreenOptions =
@@ -12,9 +13,9 @@ type ICommonScreenOptions =
export const commonScreenOptions: ICommonScreenOptions = {
title: "",
headerShown: true,
headerTransparent: true,
headerTransparent: Platform.OS === "ios",
headerShadowVisible: false,
headerBlurEffect: "none",
headerBlurEffect: Platform.OS === "ios" ? "none" : undefined,
headerLeft: () => <HeaderBackButton />,
};