0

When I sent my app to Apple for Review before going into production, they found an issue with the navigation colors. On IOS, it gets darker, I don't know why. The tricky thing here is that in Expo Go and Xcode, it renders normally

simulator and ios

Expo SDK: 53.0.9 My repo: https://github.com/crazydeveloper09/congregation_planner_rn

import { MaterialCommunityIcons } from "@expo/vector-icons";
import { createMaterialBottomTabNavigator } from "react-native-paper/react-navigation";
import MeetingsNavigator from "./Meetings";
import MinistryMeetingNavigator from "./MinistryMeetings";
import CartsScheduleNavigator from "./CartsSchedule";
import AudioVideoNavigator from "./AudioVideo";
import { Button, PaperProvider, useTheme } from "react-native-paper";
import { Context as PreachersContext } from "../contexts/PreachersContext";
import { Context as AuthContext } from "../contexts/AuthContext";
import PreachersNavigator from "./Preachers";
import SettingsNavigator from "./Settings";
import { useContext, useEffect, useState } from "react";
import useLocaLization from "../hooks/useLocalization";
import { cartScheduleTranslations } from "../screens/CartsSchedule/translations";
import { meetingsTranslations } from "../screens/Meetings/translations";
import { ministryMeetingsTranslations } from "../screens/MinistryMeeting/translations";
import { preachersTranslations } from "../screens/Preachers/translations";
import { mainTranslations } from "../../localization";
import { StatusBar, View } from "react-native";
import { Context as SettingsContext } from "../contexts/SettingsContext";
import { Platform } from "react-native";
import * as Notifications from 'expo-notifications';
import Constants from 'expo-constants';
import territories from "../api/territories";
import { buildTheme, hexToRGB } from "../helpers/colors";

const Tab = createMaterialBottomTabNavigator();

Notifications.setNotificationHandler({
    handleNotification: async () => ({
      shouldShowAlert: true,
      shouldPlaySound: true,
      shouldSetBadge: false,
    }),
  });

StatusBar.setBarStyle("light-content")

const MainNavigator = () => {
  const {state, loadPreacherInfo} = useContext(PreachersContext)
  const authContext = useContext(AuthContext);
  const cartScheduleTranslate = useLocaLization(cartScheduleTranslations);
  const meetingTranslate = useLocaLization(meetingsTranslations);
  const ministryMeetingTranslate = useLocaLization(ministryMeetingsTranslations);
  const preacherTranslate = useLocaLization(preachersTranslations);
  const mainTranslate = useLocaLization(mainTranslations);

  const settingsContext = useContext(SettingsContext);
  const [secondaryContainerColor, setSecondaryContainerColor] = useState<string>(hexToRGB(settingsContext.state.mainColor, 0.30));

  const [expoPushToken, setExpoPushToken] = useState<string | undefined>('');


  useEffect(() => {
    loadPreacherInfo(authContext.state.preacherID);
    registerForPushNotificationsAsync().then(token => setExpoPushToken(token));
    
    // Listen for incoming notifications
    const notificationListener = Notifications.addNotificationReceivedListener(notification => {
      console.log('Notification received:', notification);
      // Handle the received notification
    });

    // Handle notification when app is in foreground
    const responseListener = Notifications.addNotificationResponseReceivedListener(response => {
      console.log('Notification tapped:', response);
      // Handle the notification response
    });

    return () => {
      Notifications.removeNotificationSubscription(notificationListener);
      Notifications.removeNotificationSubscription(responseListener);
    };
  }, []);

  useEffect(() => {
    if (expoPushToken) {
      // Send the token to your backend
      sendTokenToBackend(expoPushToken, authContext.state?.preacherID!);
    }
  }, [expoPushToken]);

  useEffect(() => {
    if(settingsContext.state.loaded) {
      StatusBar.setBackgroundColor(settingsContext.state.mainColor);
      setSecondaryContainerColor(hexToRGB(settingsContext.state.mainColor, 0.30));
    }
  }, [settingsContext.state.mainColor, settingsContext.state.loaded]);

  const theme = buildTheme(settingsContext.state.mainColor);

  return (
    <PaperProvider theme={theme}>
      <Tab.Navigator
        initialRouteName="Meetings"
        barStyle={{ backgroundColor: hexToRGB(settingsContext.state.mainColor, 0.08) }}
        screenOptions={{
          tabBarColor: secondaryContainerColor,
        }}
        theme={theme}
      >
        {((state.preacher && state.preacher.roles?.includes('can_see_meetings')) || authContext.state.whoIsLoggedIn === "admin") &&  <Tab.Screen
          name="Meetings"
          component={MeetingsNavigator}
          options={{
            tabBarColor: secondaryContainerColor,
            tabBarLabel: meetingTranslate.t("sectionText"),
            tabBarIcon: ({ color }) => (
              <MaterialCommunityIcons
                name="account-tie"
                color={color}
                size={26}
              />
            ),
          }}
        /> }
        
        {((state.preacher && state.preacher.roles?.includes('can_see_minimeetings')) || authContext.state.whoIsLoggedIn === "admin") &&  <Tab.Screen
          name="MinistryMeetings"
          component={MinistryMeetingNavigator}
          options={{
            tabBarLabel: ministryMeetingTranslate.t("navText"),
            tabBarIcon: ({ color }) => (
              <MaterialCommunityIcons
                name="briefcase-variant"
                color={color}
                size={26}
              />
            ),
          }}
        /> }
      
        {((state.preacher && state.preacher.roles?.includes('can_see_cartSchedule')) || authContext.state.whoIsLoggedIn === "admin") && <Tab.Screen
          name="CartsSchedule"
          component={CartsScheduleNavigator}
          options={{
            tabBarLabel: cartScheduleTranslate.t("navText"),
            tabBarIcon: ({ color }) => (
              <MaterialCommunityIcons
                name="window-open"
                color={color}
                size={26}
              />
            ),
            
          }} //view-split-horizontal
        /> }
        {((state.preacher && state.preacher.roles?.includes('can_see_audio_video')) || authContext.state.whoIsLoggedIn === "admin") && <Tab.Screen
          name="Audio-video"
          component={AudioVideoNavigator}
          options={{
            tabBarLabel: "Audio-video",
            tabBarIcon: ({ color }) => (
              <MaterialCommunityIcons
                name="cast-audio"
                color={color}
                size={26}
              />
            ),
          }}
        /> }
        
        <Tab.Screen
          name="Settings Navigator"
          component={SettingsNavigator}
          options={{
            tabBarLabel: mainTranslate.t("settingsLabel"),
            tabBarIcon: ({ color }) => (
              <MaterialCommunityIcons
                name="cog"
                color={color}
                size={26}
              />
            ),
            
          }}
        />
      </Tab.Navigator>

    </PaperProvider>
        

      
  );
};

async function registerForPushNotificationsAsync() {
  let token;
    const { status: existingStatus } = await Notifications.getPermissionsAsync();
    let finalStatus = existingStatus;
    if (existingStatus !== 'granted') {
      const { status } = await Notifications.requestPermissionsAsync();
      finalStatus = status;
    }
    if (finalStatus !== 'granted') {
      alert('Failed to get push token for push notification!');
      return;
    }
    if (Constants.appOwnership === 'expo') {
      token = (await Notifications.getExpoPushTokenAsync()).data;
    } else {
      token = (await Notifications.getDevicePushTokenAsync()).data;
    }


  if (Platform.OS === 'android') {
    Notifications.setNotificationChannelAsync('default', {
      name: 'default',
      importance: Notifications.AndroidImportance.MAX,
      vibrationPattern: [0, 250, 250, 250],
      lightColor: '#FF231F7C',
    });
  }

  return token;
}

async function sendTokenToBackend(token: string, preacherId: string) {
  try {
    const response = await territories.post('/register-device', {
      token,
      preacherId,
      platform: Platform.OS,
    }, {
      headers: {
        'Content-Type': 'application/json',
      },
    });
  } catch (error) {
    console.error('Error sending token to backend:', error);
  }
}

export default MainNavigator;

1 Answer 1

0

The problem was with the newest version of Expo 52/53. Here, iOS doesn't correctly read alpha colors. I need to use the tinycolors library to lighten the color and transform it to a hex string.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.