Merge pull request 'fix: replace broken swipe-to-refresh with toolbar button (#61)' (#67) from issue-61-refresh-button-toolbar into master
This commit is contained in:
commit
fe43b65cfd
2 changed files with 60 additions and 26 deletions
|
|
@ -1,7 +1,7 @@
|
|||
import { useEffect, useState, useCallback, useRef } from 'react';
|
||||
import { View, Text, Pressable, TextInput, useColorScheme, Alert, RefreshControl } from 'react-native';
|
||||
import { View, Text, Pressable, TextInput, useColorScheme, Alert, Animated, Easing } from 'react-native';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { Plus, ArrowUpDown, Filter, Download, Search, X } from 'lucide-react-native';
|
||||
import { Plus, ArrowUpDown, Filter, Download, Search, X, RefreshCw } from 'lucide-react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import DraggableFlatList, { RenderItemParams } from 'react-native-draggable-flatlist';
|
||||
|
|
@ -45,6 +45,7 @@ export default function InboxScreen() {
|
|||
const isDark = (theme === 'system' ? systemScheme : theme) === 'dark';
|
||||
const isDraggingRef = useRef(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const spinAnim = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const { sortBy, sortOrder, filterPriority, filterTag, filterCompleted, filterDueDate, hasActiveFilters } = useTaskStore();
|
||||
|
||||
|
|
@ -72,10 +73,29 @@ export default function InboxScreen() {
|
|||
}, [loadTasks]);
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
if (refreshing) return;
|
||||
setRefreshing(true);
|
||||
await loadTasks();
|
||||
setRefreshing(false);
|
||||
}, [loadTasks]);
|
||||
spinAnim.setValue(0);
|
||||
Animated.loop(
|
||||
Animated.timing(spinAnim, {
|
||||
toValue: 1,
|
||||
duration: 800,
|
||||
easing: Easing.linear,
|
||||
useNativeDriver: true,
|
||||
})
|
||||
).start();
|
||||
try {
|
||||
await loadTasks();
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
spinAnim.stopAnimation();
|
||||
}
|
||||
}, [loadTasks, refreshing, spinAnim]);
|
||||
|
||||
const spin = spinAnim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '360deg'],
|
||||
});
|
||||
|
||||
const handleToggle = async (id: string) => {
|
||||
await toggleComplete(id);
|
||||
|
|
@ -171,6 +191,11 @@ export default function InboxScreen() {
|
|||
</View>
|
||||
) : (
|
||||
<View className={`flex-row items-center justify-end border-b px-4 py-2 ${isDark ? 'border-[#3A3A3A]' : 'border-[#E5E7EB]'}`}>
|
||||
<Pressable onPress={handleRefresh} disabled={refreshing} className="mr-3 p-1">
|
||||
<Animated.View style={{ transform: [{ rotate: spin }] }}>
|
||||
<RefreshCw size={20} color={isDark ? '#A0A0A0' : '#6B6B6B'} />
|
||||
</Animated.View>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => setShowSearch(true)} className="mr-3 p-1">
|
||||
<Search size={20} color={isDark ? '#A0A0A0' : '#6B6B6B'} />
|
||||
</Pressable>
|
||||
|
|
@ -208,14 +233,6 @@ export default function InboxScreen() {
|
|||
onDragBegin={() => { isDraggingRef.current = true; }}
|
||||
onDragEnd={handleDragEnd}
|
||||
activationDistance={canDrag ? 0 : 10000}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
tintColor={colors.bleu.DEFAULT}
|
||||
colors={[colors.bleu.DEFAULT]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</GestureHandlerRootView>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { useEffect, useState, useCallback, useRef } from 'react';
|
||||
import { View, Text, Pressable, TextInput, useColorScheme, Alert, RefreshControl } from 'react-native';
|
||||
import { View, Text, Pressable, TextInput, useColorScheme, Alert, Animated, Easing } from 'react-native';
|
||||
import { useRouter, useLocalSearchParams } from 'expo-router';
|
||||
import {
|
||||
ArrowLeft, Plus, ArrowUpDown, Filter, Download, Search, X,
|
||||
ArrowLeft, Plus, ArrowUpDown, Filter, Download, Search, X, RefreshCw,
|
||||
List, ShoppingCart, Briefcase, Home, Heart, Star, BookOpen,
|
||||
GraduationCap, Dumbbell, Utensils, Plane, Music, Code, Wrench,
|
||||
Gift, Camera, Palette, Dog, Leaf, Zap,
|
||||
|
|
@ -62,6 +62,7 @@ export default function ListDetailScreen() {
|
|||
const isDark = (theme === 'system' ? systemScheme : theme) === 'dark';
|
||||
const isDraggingRef = useRef(false);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const spinAnim = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const { sortBy, sortOrder, filterPriority, filterTag, filterCompleted, filterDueDate, hasActiveFilters } = useTaskStore();
|
||||
|
||||
|
|
@ -97,10 +98,29 @@ export default function ListDetailScreen() {
|
|||
}, [loadData]);
|
||||
|
||||
const handleRefresh = useCallback(async () => {
|
||||
if (refreshing) return;
|
||||
setRefreshing(true);
|
||||
await loadData();
|
||||
setRefreshing(false);
|
||||
}, [loadData]);
|
||||
spinAnim.setValue(0);
|
||||
Animated.loop(
|
||||
Animated.timing(spinAnim, {
|
||||
toValue: 1,
|
||||
duration: 800,
|
||||
easing: Easing.linear,
|
||||
useNativeDriver: true,
|
||||
})
|
||||
).start();
|
||||
try {
|
||||
await loadData();
|
||||
} finally {
|
||||
setRefreshing(false);
|
||||
spinAnim.stopAnimation();
|
||||
}
|
||||
}, [loadData, refreshing, spinAnim]);
|
||||
|
||||
const spin = spinAnim.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '360deg'],
|
||||
});
|
||||
|
||||
const handleToggle = async (taskId: string) => {
|
||||
await toggleComplete(taskId);
|
||||
|
|
@ -199,6 +219,11 @@ export default function ListDetailScreen() {
|
|||
</Text>
|
||||
</View>
|
||||
<View className="flex-row items-center">
|
||||
<Pressable onPress={handleRefresh} disabled={refreshing} className="mr-3 p-1">
|
||||
<Animated.View style={{ transform: [{ rotate: spin }] }}>
|
||||
<RefreshCw size={20} color={isDark ? '#A0A0A0' : '#6B6B6B'} />
|
||||
</Animated.View>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => setShowSearch(true)} className="mr-3 p-1">
|
||||
<Search size={20} color={isDark ? '#A0A0A0' : '#6B6B6B'} />
|
||||
</Pressable>
|
||||
|
|
@ -256,14 +281,6 @@ export default function ListDetailScreen() {
|
|||
onDragBegin={() => { isDraggingRef.current = true; }}
|
||||
onDragEnd={handleDragEnd}
|
||||
activationDistance={canDrag ? 0 : 10000}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={refreshing}
|
||||
onRefresh={handleRefresh}
|
||||
tintColor={colors.bleu.DEFAULT}
|
||||
colors={[colors.bleu.DEFAULT]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</GestureHandlerRootView>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Reference in a new issue