feat(Notification): implement notification preferences management and enhance notification handling
- Introduced a new service for managing notification preferences, including push notifications, sound, and vibration settings. - Updated the notification handling logic to respect user preferences, ensuring notifications are displayed according to user settings. - Refactored the App and various screens to integrate the new notification preferences, improving user experience and consistency. - Enhanced the HomeScreen and NotificationSettingsScreen to load and update notification settings seamlessly. - Implemented a mechanism to hide the bottom tab bar based on scroll events, improving navigation usability.
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import { useMemo } from 'react';
|
||||
import { Platform, useWindowDimensions } from 'react-native';
|
||||
import { Tabs } from 'expo-router';
|
||||
import { Tabs, usePathname } from 'expo-router';
|
||||
import { MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
import { colors, shadows } from '../../../src/theme';
|
||||
import { BREAKPOINTS } from '../../../src/hooks/useResponsive';
|
||||
import { useTotalUnreadCount } from '../../../src/stores';
|
||||
import { useHomeTabBarVisibilityStore, useTotalUnreadCount } from '../../../src/stores';
|
||||
|
||||
const TAB_BAR_HEIGHT = 56;
|
||||
const TAB_BAR_FLOATING_MARGIN = 12;
|
||||
@@ -14,31 +15,50 @@ const TAB_BAR_MARGIN = 20;
|
||||
export default function TabsLayout() {
|
||||
const { width } = useWindowDimensions();
|
||||
const insets = useSafeAreaInsets();
|
||||
const pathname = usePathname();
|
||||
const unreadCount = useTotalUnreadCount();
|
||||
const scrollHideTabBar = useHomeTabBarVisibilityStore((s) => s.bottomTabBarHiddenByScroll);
|
||||
const hideTabBar = Platform.OS === 'web' && width >= BREAKPOINTS.desktop;
|
||||
|
||||
const isHomeStackRoute = pathname === '/home' || pathname.startsWith('/home/');
|
||||
|
||||
const tabBarStyle = useMemo(() => {
|
||||
if (hideTabBar) {
|
||||
return { display: 'none' as const, height: 0, overflow: 'hidden' as const };
|
||||
}
|
||||
const visibleStyle = {
|
||||
position: 'absolute' as const,
|
||||
left: 0,
|
||||
right: 0,
|
||||
marginHorizontal: TAB_BAR_MARGIN,
|
||||
bottom: TAB_BAR_FLOATING_MARGIN + insets.bottom,
|
||||
height: TAB_BAR_HEIGHT,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.background.paper,
|
||||
...shadows.lg,
|
||||
borderTopWidth: 0,
|
||||
elevation: 100,
|
||||
zIndex: 100,
|
||||
};
|
||||
if (isHomeStackRoute && scrollHideTabBar) {
|
||||
return {
|
||||
...visibleStyle,
|
||||
display: 'none' as const,
|
||||
height: 0,
|
||||
opacity: 0,
|
||||
overflow: 'hidden' as const,
|
||||
};
|
||||
}
|
||||
return visibleStyle;
|
||||
}, [hideTabBar, insets.bottom, isHomeStackRoute, scrollHideTabBar]);
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
screenOptions={{
|
||||
headerShown: false,
|
||||
tabBarActiveTintColor: colors.primary.main,
|
||||
tabBarInactiveTintColor: colors.text.secondary,
|
||||
tabBarStyle: hideTabBar
|
||||
? { display: 'none', height: 0, overflow: 'hidden' }
|
||||
: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
marginHorizontal: TAB_BAR_MARGIN,
|
||||
bottom: TAB_BAR_FLOATING_MARGIN + insets.bottom,
|
||||
height: TAB_BAR_HEIGHT,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.background.paper,
|
||||
...shadows.lg,
|
||||
borderTopWidth: 0,
|
||||
elevation: 100,
|
||||
zIndex: 100,
|
||||
},
|
||||
tabBarStyle,
|
||||
tabBarItemStyle: {
|
||||
borderRadius: 16,
|
||||
marginHorizontal: 2,
|
||||
@@ -62,13 +82,12 @@ export default function TabsLayout() {
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="messages"
|
||||
name="apps"
|
||||
options={{
|
||||
title: '消息',
|
||||
tabBarBadge: unreadCount > 0 ? (unreadCount > 99 ? 99 : unreadCount) : undefined,
|
||||
title: '应用',
|
||||
tabBarIcon: ({ color, focused }) => (
|
||||
<MaterialCommunityIcons
|
||||
name={focused ? 'message-text' : 'message-text-outline'}
|
||||
name={focused ? 'view-grid' : 'view-grid-outline'}
|
||||
size={focused ? 24 : 22}
|
||||
color={color}
|
||||
/>
|
||||
@@ -76,12 +95,13 @@ export default function TabsLayout() {
|
||||
}}
|
||||
/>
|
||||
<Tabs.Screen
|
||||
name="apps"
|
||||
name="messages"
|
||||
options={{
|
||||
title: '应用',
|
||||
title: '消息',
|
||||
tabBarBadge: unreadCount > 0 ? (unreadCount > 99 ? 99 : unreadCount) : undefined,
|
||||
tabBarIcon: ({ color, focused }) => (
|
||||
<MaterialCommunityIcons
|
||||
name={focused ? 'view-grid' : 'view-grid-outline'}
|
||||
name={focused ? 'message-text' : 'message-text-outline'}
|
||||
size={focused ? 24 : 22}
|
||||
color={color}
|
||||
/>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { PaperProvider } from 'react-native-paper';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import * as Notifications from 'expo-notifications';
|
||||
|
||||
import { registerNotificationPresentationHandler } from '../src/services/notificationPreferences';
|
||||
import { paperTheme } from '../src/theme';
|
||||
import { AppBackButton } from '../src/components/common';
|
||||
import AppPromptBar from '../src/components/common/AppPromptBar';
|
||||
@@ -16,15 +17,7 @@ import { installAlertOverride } from '../src/services/alertOverride';
|
||||
import { useAuthStore } from '../src/stores';
|
||||
import { colors } from '../src/theme';
|
||||
|
||||
Notifications.setNotificationHandler({
|
||||
handleNotification: async () => ({
|
||||
shouldShowAlert: true,
|
||||
shouldPlaySound: true,
|
||||
shouldSetBadge: true,
|
||||
shouldShowBanner: true,
|
||||
shouldShowList: true,
|
||||
}),
|
||||
});
|
||||
registerNotificationPresentationHandler();
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
@@ -78,6 +71,8 @@ function NotificationBootstrap() {
|
||||
|
||||
useEffect(() => {
|
||||
const initNotifications = async () => {
|
||||
const { loadNotificationPreferences } = await import('../src/services/notificationPreferences');
|
||||
await loadNotificationPreferences();
|
||||
const { systemNotificationService } = await import('../src/services/systemNotificationService');
|
||||
await systemNotificationService.initialize();
|
||||
const { initBackgroundService } = await import('../src/services/backgroundService');
|
||||
|
||||
Reference in New Issue
Block a user