refresh button, calendar margins

This commit is contained in:
ivic00
2024-12-05 11:32:54 +01:00
parent 1b288d095f
commit 8526d79ba1
6 changed files with 436 additions and 317 deletions

View File

@ -1,8 +1,18 @@
import React from "react"; import React from "react";
import { Drawer } from "expo-router/drawer"; import { Drawer } from "expo-router/drawer";
import { useSignOut } from "@/hooks/firebase/useSignOut"; import { useSignOut } from "@/hooks/firebase/useSignOut";
import {DrawerContentScrollView, DrawerNavigationOptions, DrawerNavigationProp} from "@react-navigation/drawer"; import {
import {Button, ButtonSize, Text, TouchableOpacity, View,} from "react-native-ui-lib"; DrawerContentScrollView,
DrawerNavigationOptions,
DrawerNavigationProp,
} from "@react-navigation/drawer";
import {
Button,
ButtonSize,
Text,
TouchableOpacity,
View,
} from "react-native-ui-lib";
import { ImageBackground, StyleSheet } from "react-native"; import { ImageBackground, StyleSheet } from "react-native";
import DrawerButton from "@/components/shared/DrawerButton"; import DrawerButton from "@/components/shared/DrawerButton";
import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon"; import NavGroceryIcon from "@/assets/svgs/NavGroceryIcon";
@ -24,6 +34,8 @@ import {DeviceType} from "expo-device";
import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon"; import FeedbackNavIcon from "@/assets/svgs/FeedbackNavIcon";
import DrawerIcon from "@/assets/svgs/DrawerIcon"; import DrawerIcon from "@/assets/svgs/DrawerIcon";
import { RouteProp } from "@react-navigation/core"; import { RouteProp } from "@react-navigation/core";
import RefreshButton from "@/components/shared/RefreshButton";
import { useCalSync } from "@/hooks/useCalSync";
type DrawerParamList = { type DrawerParamList = {
index: undefined; index: undefined;
@ -43,12 +55,11 @@ interface HeaderRightProps {
} }
const MemoizedViewSwitch = React.memo<ViewSwitchProps>(({ navigation }) => ( const MemoizedViewSwitch = React.memo<ViewSwitchProps>(({ navigation }) => (
<View marginR-16>
<ViewSwitch navigation={navigation} /> <ViewSwitch navigation={navigation} />
</View>
)); ));
const HeaderRight = React.memo<HeaderRightProps>(({routeName, navigation}) => { const HeaderRight = React.memo<HeaderRightProps>(
({ routeName, navigation }) => {
const showViewSwitch = ["calendar", "todos", "index"].includes(routeName); const showViewSwitch = ["calendar", "todos", "index"].includes(routeName);
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) { if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
@ -56,13 +67,23 @@ const HeaderRight = React.memo<HeaderRightProps>(({routeName, navigation}) => {
} }
return <MemoizedViewSwitch navigation={navigation} />; return <MemoizedViewSwitch navigation={navigation} />;
}); }
);
export default function TabLayout() { export default function TabLayout() {
const { mutateAsync: signOut } = useSignOut(); const { mutateAsync: signOut } = useSignOut();
const setIsFamilyView = useSetAtom(isFamilyViewAtom); const setIsFamilyView = useSetAtom(isFamilyViewAtom);
const setPageIndex = useSetAtom(settingsPageIndex); const setPageIndex = useSetAtom(settingsPageIndex);
const setUserView = useSetAtom(userSettingsView); const setUserView = useSetAtom(userSettingsView);
const setToDosIndex = useSetAtom(toDosPageIndex); const setToDosIndex = useSetAtom(toDosPageIndex);
const { resyncAllCalendars, isSyncing } = useCalSync();
const onRefresh = React.useCallback(async () => {
try {
await resyncAllCalendars();
} catch (error) {
console.error("Refresh failed:", error);
}
}, [resyncAllCalendars]);
const screenOptions = ({ const screenOptions = ({
navigation, navigation,
@ -72,7 +93,8 @@ export default function TabLayout() {
route: RouteProp<DrawerParamList>; route: RouteProp<DrawerParamList>;
}): DrawerNavigationOptions => ({ }): DrawerNavigationOptions => ({
headerShown: true, headerShown: true,
headerTitleAlign: Device.deviceType === DeviceType.TABLET ? "left" : "center", headerTitleAlign:
Device.deviceType === DeviceType.TABLET ? "left" : "center",
headerTitleStyle: { headerTitleStyle: {
fontFamily: "Manrope_600SemiBold", fontFamily: "Manrope_600SemiBold",
fontSize: Device.deviceType === DeviceType.TABLET ? 22 : 17, fontSize: Device.deviceType === DeviceType.TABLET ? 22 : 17,
@ -86,20 +108,31 @@ export default function TabLayout() {
</TouchableOpacity> </TouchableOpacity>
), ),
headerRight: () => { headerRight: () => {
const showViewSwitch = ["calendar", "todos", "index"].includes(route.name); const showViewSwitch = ["calendar", "todos", "index"].includes(
route.name
);
if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) { if (Device.deviceType !== DeviceType.TABLET || !showViewSwitch) {
return null; return (
<View marginR-16>
<RefreshButton onRefresh={onRefresh} isSyncing={isSyncing} />
</View>
);
} }
return <MemoizedViewSwitch navigation={navigation}/>; return (
<View marginR-16 row>
<RefreshButton onRefresh={onRefresh} isSyncing={isSyncing} />
<MemoizedViewSwitch navigation={navigation} />
</View>
);
}, },
drawerStyle: { drawerStyle: {
width: Device.deviceType === DeviceType.TABLET ? "30%" : "90%", width: Device.deviceType === DeviceType.TABLET ? "30%" : "90%",
backgroundColor: "#f9f8f7", backgroundColor: "#f9f8f7",
height: "100%", height: "100%",
}, },
}) });
return ( return (
<Drawer <Drawer

View File

@ -61,7 +61,6 @@ export default function Screen() {
justifyContent: "center", justifyContent: "center",
paddingRight: 200, paddingRight: 200,
}} }}
refreshControl={refreshControl}
bounces={true} bounces={true}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
pointerEvents={isSyncing ? "auto" : "none"} pointerEvents={isSyncing ? "auto" : "none"}
@ -74,7 +73,6 @@ export default function Screen() {
<ScrollView <ScrollView
style={{flex: 1, height: "100%"}} style={{flex: 1, height: "100%"}}
contentContainerStyle={{flex: 1, height: "100%"}} contentContainerStyle={{flex: 1, height: "100%"}}
refreshControl={refreshControl}
bounces={true} bounces={true}
showsVerticalScrollIndicator={false} showsVerticalScrollIndicator={false}
> >

View File

@ -0,0 +1,20 @@
import * as React from "react"
import Svg, { SvgProps, Path } from "react-native-svg"
const CheckmarkIcon = (props: SvgProps) => (
<Svg
width={13}
height={10}
viewBox="0 0 13 10"
fill={props.color || "white"}
{...props}
>
<Path
stroke="#fff"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={1.95}
d="m1.48 5.489 3.2 3.178 7.2-7.15"
/>
</Svg>
)
export default CheckmarkIcon

View File

@ -5,9 +5,9 @@ import { InnerCalendar } from "@/components/pages/calendar/InnerCalendar";
export default function CalendarPage() { export default function CalendarPage() {
return ( return (
<View <View
style={{ flex: 1, height: "100%", padding: 10 }} style={{ flex: 1, height: "100%", padding: 0 }}
paddingH-22 paddingH-0
paddingT-22 paddingT-0
> >
{/*<HeaderTemplate {/*<HeaderTemplate
message={"Let's get your week started !"} message={"Let's get your week started !"}

View File

@ -25,9 +25,10 @@ export const InnerCalendar = () => {
return ( return (
<> <>
<View <View
style={{flex: 1, backgroundColor: "#fff", borderRadius: 30, marginBottom: 10, overflow: "hidden"}} style={{flex: 1, backgroundColor: "#fff", borderRadius: 0, marginBottom: 0, overflow: "hidden"}}
ref={calendarContainerRef} ref={calendarContainerRef}
onLayout={onLayout} onLayout={onLayout}
paddingB-15
> >
<CalendarHeader/> <CalendarHeader/>
{calendarHeight > 0 && ( {calendarHeight > 0 && (

View File

@ -0,0 +1,67 @@
import React, { useRef, useEffect } from 'react';
import { TouchableOpacity, Animated, Easing } from 'react-native';
import { Feather } from '@expo/vector-icons';
interface RefreshButtonProps {
onRefresh: () => Promise<void>;
isSyncing: boolean;
size?: number;
color?: string;
}
const RefreshButton = ({
onRefresh,
isSyncing,
size = 24,
color = "#83807F"
}: RefreshButtonProps) => {
const rotateAnim = useRef(new Animated.Value(0)).current;
const rotationLoop = useRef<Animated.CompositeAnimation | null>(null);
useEffect(() => {
if (isSyncing) {
startContinuousRotation();
} else {
stopRotation();
}
}, [isSyncing]);
const startContinuousRotation = () => {
rotateAnim.setValue(0);
rotationLoop.current = Animated.loop(
Animated.timing(rotateAnim, {
toValue: 1,
duration: 1000,
easing: Easing.linear,
useNativeDriver: true,
})
);
rotationLoop.current.start();
};
const stopRotation = () => {
rotationLoop.current?.stop();
rotateAnim.setValue(0);
};
const rotate = rotateAnim.interpolate({
inputRange: [0, 1],
outputRange: ['0deg', '360deg'],
});
const handlePress = async () => {
if (!isSyncing) {
await onRefresh();
}
};
return (
<TouchableOpacity onPress={handlePress} disabled={isSyncing}>
<Animated.View style={{ transform: [{ rotate }] }}>
<Feather name="refresh-cw" size={size} color={color} />
</Animated.View>
</TouchableOpacity>
);
};
export default RefreshButton;