Pomodoro en React Native - Pomodoro in React Native

Pomodoro en React Native - Pomodoro in React Native

Productivity25x5x10

Introducción - Introduction

Nuestra aplicación Timer Pomodoro te ofrece intervalos de 5, 10 y 25 minutos para ayudarte a enfocarte y ser más productivo. Cuando cada intervalo llega a su fin, se activa una alarma que te ayuda a mantener la concentración. Además, la aplicación cuenta con un modo de fondo que te permite seguir utilizando tu dispositivo mientras el temporizador está en funcionamiento.

Our Pomodoro Timer app provides you with intervals of 5, 10, and 25 minutes to help you stay focused and be more productive. When each interval comes to an end, an alarm sounds to help you maintain concentration. Additionally, the app features a background mode that allows you to continue using your device while the timer is running.

npm Packages

  1. https://www.npmjs.com/package/@react-navigation/native

  2. https://www.npmjs.com/package/react-native-screens

  3. https://www.npmjs.com/package/react-native-safe-area-context

  4. https://www.npmjs.com/package/react-native-tab-view

  5. https://www.npmjs.com/package/react-native-pager-view

  6. https://www.npmjs.com/package/react-native-vector-icons

  7. https://rntp.dev/

  8. https://www.npmjs.com/package/react-native-background-timer

  9. https://www.npmjs.com/package/@sayem314/react-native-keep-awake

  10. https://oblador.github.io/react-native-vector-icons/

Servicio - Service

constants.ts

import { Track } from "react-native-track-player";

export const playListData: Track[] = [
    {
      id: 1,
      title: 'alarma',
      artist: 'personal',
      album: 'personal',
      artwork:
        '',
      url: require('./assets/audio/alarma.mp3'),
    }
  ];

Importaciones

import { Track } from "react-native-track-player";

Aquí estamos importando el modelo Track de la biblioteca react-native-track-player, que representa una pista de audio.

Definición de la lista de pistas

export const playListData: Track[] = [
  {
    id: 1,
    title: 'alarma',
    artist: 'personal',
    album: 'personal',
    artwork: '',
    url: require('./assets/audio/alarma.mp3'),
  }
];

Definimos una lista de pistas de tipo Track[] llamada playListData que contiene un objeto con los datos de una pista: id, título, artista, álbum, portada y URL.

Imports

import { Track } from "react-native-track-player";

Here we are importing the Track model from the react-native-track-player library, which represents an audio track.

musicPlayerServices.js

import TrackPlayer, { Event, RepeatMode, Capability } from "react-native-track-player";
import { playListData } from './src/constants';



export async function setupPlayer() {
     let isSetup = false;
    try {
        await TrackPlayer.getCurrentTrack();
        isSetup = true;
    } catch (error) {
        await TrackPlayer.setupPlayer();
        isSetup = true;
    } finally {
        return isSetup;
    }
}

export async function addTrack() {
    await TrackPlayer.add(playListData);
    await TrackPlayer.setRepeatMode(RepeatMode.Queue);
}

export async function playbackService() {
    await TrackPlayer.updateOptions({
        capabilities: [
            Capability.Play,
            Capability.Pause,
            Capability.SkipToNext,
            Capability.SkipToPrevious,
            Capability.Stop
        ],
        compactCapabilities: [Capability.Play, Capability.Pause, Capability.Stop],
    });

    TrackPlayer.addEventListener(Event.RemotePause, () => {
        TrackPlayer.pause();
    });

    TrackPlayer.addEventListener(Event.RemotePlay, () => {
        TrackPlayer.play();
    });

    TrackPlayer.addEventListener(Event.RemoteNext, () => {
        TrackPlayer.skipToNext();
    });

    TrackPlayer.addEventListener(Event.RemotePrevious, () => {
        TrackPlayer.skipToPrevious();
    });

    TrackPlayer.addEventListener(Event.RemoteStop, () => {
        TrackPlayer.stop();
    });
}

Importaciones

import TrackPlayer, { Event, RepeatMode, Capability } from "react-native-track-player";
import { playListData } from './src/constants';

Aquí estamos importando el módulo TrackPlayer de la biblioteca react-native-track-player, que nos permite reproducir audio en segundo plano en una aplicación React Native. También importamos algunas constantes específicas de este módulo: Event, RepeatMode y Capability. Además, importamos playListData de un archivo de constantes en nuestro proyecto.

setupPlayer()

export async function setupPlayer() {
     let isSetup = false;
    try {
        await TrackPlayer.getCurrentTrack();
        isSetup = true;
    } catch (error) {
        await TrackPlayer.setupPlayer();
        isSetup = true;
    } finally {
        return isSetup;
    }
}

Esta función asincrónica intenta obtener la pista actual que se está reproduciendo. Si puede obtenerla, significa que el reproductor ya está configurado, por lo que establece isSetup en true. Si no puede obtenerla y se produce un error, entonces configura el reproductor y establece isSetup en true. Finalmente, la función devuelve el valor de isSetup.

addTrack()

export async function addTrack() {
    await TrackPlayer.add(playListData);
    await TrackPlayer.setRepeatMode(RepeatMode.Queue);
}

Esta función asincrónica agrega las pistas de playListData al reproductor y establece el modo de repetición en RepeatMode.Queue, lo que significa que la lista de reproducción comenzará de nuevo una vez que se hayan reproducido todas las pistas.

playbackService()

export async function playbackService() {
    await TrackPlayer.updateOptions({
        capabilities: [
            Capability.Play,
            Capability.Pause,
            Capability.SkipToNext,
            Capability.SkipToPrevious,
            Capability.Stop
        ],
        compactCapabilities: [Capability.Play, Capability.Pause, Capability.Stop],
    });

    TrackPlayer.addEventListener(Event.RemotePause, () => {
        TrackPlayer.pause();
    });

    TrackPlayer.addEventListener(Event.RemotePlay, () => {
        TrackPlayer.play();
    });

    TrackPlayer.addEventListener(Event.RemoteNext, () => {
        TrackPlayer.skipToNext();
    });

    TrackPlayer.addEventListener(Event.RemotePrevious, () => {
        TrackPlayer.skipToPrevious();
    });

    TrackPlayer.addEventListener(Event.RemoteStop, () => {
        TrackPlayer.stop();
    });
}

Esta función asincrónica actualiza las opciones del reproductor, estableciendo las capacidades que puede manejar (reproducir, pausar, saltar a la siguiente pista, saltar a la pista anterior, detener) y las capacidades compactas (reproducir, pausar, detener). Luego, configura varios oyentes de eventos para manejar los controles remotos de pausa, reproducción, siguiente, anterior y detener.

Imports

import TrackPlayer, { Event, RepeatMode, Capability } from "react-native-track-player";
import { playListData } from './src/constants';

Here we are importing the TrackPlayer module from the react-native-track-player library, which allows us to play audio in the background in a React Native application. We also import some specific constants from this module: Event, RepeatMode, and Capability. In addition, we import playListData from a constants file in our project.

setupPlayer()

export async function setupPlayer() {
     let isSetup = false;
    try {
        await TrackPlayer.getCurrentTrack();
        isSetup = true;
    } catch (error) {
        await TrackPlayer.setupPlayer();
        isSetup = true;
    } finally {
        return isSetup;
    }
}

This asynchronous function tries to get the current track that is playing. If it can get it, it means the player is already set up, so it sets isSetup to true. If it can't get it and an error occurs, then it sets up the player and sets isSetup to true. Finally, the function returns the value of isSetup.

index.js

import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
import TrackPlayer from 'react-native-track-player';
import { setupPlayer, playbackService } from './musicPlayerServices';

AppRegistry.registerComponent(appName, () => App);


(async () => {
    await setupPlayer();
    TrackPlayer.registerPlaybackService(() => playbackService);
})();

Importaciones

import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
import TrackPlayer from 'react-native-track-player';
import { setupPlayer, playbackService } from './musicPlayerServices';

Aquí estamos importando los módulos necesarios para configurar la aplicación y el reproductor de pistas de música. AppRegistry se utiliza para registrar el componente principal de la aplicación, App es el componente principal de la aplicación, appName es el nombre de la aplicación, TrackPlayer es el reproductor de pistas de música, y setupPlayer y playbackService son funciones para configurar y controlar el reproductor de pistas de música.

Registro del Componente

AppRegistry.registerComponent(appName, () => App);

Aquí estamos registrando el componente principal de la aplicación utilizando AppRegistry.

Configuración del Reproductor y Registro del Servicio de Reproducción

(async () => {
    await setupPlayer();
    TrackPlayer.registerPlaybackService(() => playbackService);
})();

Esta función asincrónica se autoinvoca y primero configura el reproductor de pistas de música utilizando la función setupPlayer. Luego registra el servicio de reproducción utilizando TrackPlayer.registerPlaybackService y la función playbackService.

Imports

import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
import TrackPlayer from 'react-native-track-player';
import { setupPlayer, playbackService } from './musicPlayerServices';

Here we are importing the necessary modules to set up the application and the music track player. AppRegistry is used to register the main component of the application, App is the main component of the application, appName is the name of the application, TrackPlayer is the music track player, and setupPlayer and playbackService are functions to set up and control the music track player.

Component Registration

AppRegistry.registerComponent(appName, () => App);

Here we are registering the main component of the application using AppRegistry.

Player Setup and Playback Service Registration

(async () => {
    await setupPlayer();
    TrackPlayer.registerPlaybackService(() => playbackService);
})();

This self-invoking asynchronous function first sets up the music track player using the setupPlayer function. It then registers the playback service using TrackPlayer.registerPlaybackService and the playbackService function.

Components

FiveMinutesScreen.tsx

import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TrackPlayer, { State, usePlaybackState, Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import BackgroundTimer from 'react-native-background-timer';
import { setupPlayer, playbackService } from '../../musicPlayerServices';
import KeepAwake, { useKeepAwake,activateKeepAwake, deactivateKeepAwake  } from '@sayem314/react-native-keep-awake';


const FiveMinutesScreen = () => {
    const [stopped, setStopped] = useState(true);
    const [paused, setPaused] = useState(true);
    const [minutes, setMinutes] = useState(5);
    const [seconds, setSeconds] = useState(0);
    const [temporizadorFinalizado, setTemporizadorFinalizado] = useState(false);
    const [track, setTrack] = useState<Track | null>();



    useTrackPlayerEvents([Event.PlaybackTrackChanged], async event => {
        switch (event.type) {
            case Event.PlaybackTrackChanged:
                const playingTrack = await TrackPlayer.getTrack(event.nextTrack)
                setTrack(playingTrack)
                break;
        }
    });

    const playbackState = usePlaybackState();

    const play = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
            if (playback === State.Stopped || playback === State.Ready) {
                await TrackPlayer.play()
            }
        }
    }

    const stop = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
            if (playback === State.Playing) {                
                await TrackPlayer.pause(); 
                await TrackPlayer.seekTo(0);                
            }
        }
    }

    const startTimer = () => {
        if (temporizadorFinalizado) {
            setMinutes(5);
            setSeconds(0);

        }
        setStopped(false);
        setPaused(false);
        setTemporizadorFinalizado(false);
    };

    const pauseTimer = () => {
        setPaused(true);
        setTemporizadorFinalizado(false);
    };

    const stopTimer = () => {
        setStopped(true);
        setPaused(false);
        setMinutes(5);
        setSeconds(0);
        stop(playbackState);
        setTemporizadorFinalizado(true);
    };

    const resetTimer = () => {
        setStopped(true);
        setPaused(true);
        setMinutes(5);
        setSeconds(0);
    };

    useEffect(() => {
        let interval: number;
        if (!stopped && !paused) {
            interval = BackgroundTimer.setInterval(() => {
                if (seconds > 0) {
                    setSeconds(seconds - 1);
                } else {
                    if (minutes === 0) {                        
                        BackgroundTimer.clearInterval(interval);
                        setStopped(true);
                        setTemporizadorFinalizado(true);
                        play(playbackState);                        
                    } else {
                        setMinutes(minutes - 1);
                        setSeconds(59);
                    }
                }
            }, 1000);
        }



        return () => {
            if (interval) {
                BackgroundTimer.clearInterval(interval);

            }
        };
    }, [stopped, paused, minutes, seconds]);

    return (
        <View style={styles.container}>
             <KeepAwake  />
            <Text style={styles.timerText}>
                0{minutes}:{seconds < 10 ? `0${seconds}` : seconds}
            </Text>
            <View style={styles.iconContainer}>
                <Icon
                    name={paused ? 'play-box' : 'pause-octagon'}
                    size={100}
                    color="#192A56"
                    onPress={paused ? startTimer : pauseTimer}
                />
                <Icon
                    name={temporizadorFinalizado ? 'stop' : 'restore'}
                    size={100}
                    color="#192A56"
                    onPress={temporizadorFinalizado ? stopTimer : resetTimer}
                />
            </View>
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#F0DF87',
    },
    timerText: {
        fontSize: 100,
        fontWeight: 'bold',
        marginBottom: 10,
        color: '#192A56',
    },
    iconContainer: {
        flexDirection: 'row',
        justifyContent: 'space-around',
        marginTop: 20,
    },
});

export default FiveMinutesScreen;

El código proporcionado es un componente de React llamado FiveMinutesScreen que utiliza varios hooks y módulos de React Native para implementar un temporizador de cuenta regresiva de cinco minutos. Aquí está el desglose paso a paso del código:

Importaciones

import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TrackPlayer, { State, usePlaybackState, Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import BackgroundTimer from 'react-native-background-timer';
import { setupPlayer, playbackService } from '../../musicPlayerServices';
import KeepAwake, { useKeepAwake,activateKeepAwake, deactivateKeepAwake  } from '@sayem314/react-native-keep-awake';

Aquí se importan los módulos y hooks necesarios para el componente, incluyendo componentes de React Native, iconos, TrackPlayer para la reproducción de audio, BackgroundTimer para el temporizador en segundo plano, y KeepAwake para mantener despierto el dispositivo.

Función FiveMinutesScreen

La función FiveMinutesScreen es el componente principal que renderiza la pantalla del temporizador de cinco minutos. Utiliza estados locales para controlar el estado del temporizador, los minutos, los segundos, etc. También utiliza varios hooks de React, como useEffect y useState, para manejar la lógica del temporizador y la reproducción de audio.

Eventos y Funciones de Control de Reproducción

El componente utiliza el hook useTrackPlayerEvents para manejar eventos de cambio de pista de reproducción. También define funciones para controlar la reproducción y pausa de pistas de audio.

Lógica del Temporizador

Dentro del hook useEffect, se implementa la lógica del temporizador utilizando BackgroundTimer para contar el tiempo y actualizar el estado del temporizador.

The provided code is a React component called FiveMinutesScreen that uses various React Native hooks and modules to implement a five-minute countdown timer. Here's the step-by-step breakdown of the code:

Imports

import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TrackPlayer, { State, usePlaybackState, Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import BackgroundTimer from 'react-native-background-timer';
import { setupPlayer, playbackService } from '../../musicPlayerServices';
import KeepAwake, { useKeepAwake,activateKeepAwake, deactivateKeepAwake  } from '@sayem314/react-native-keep-awake';

Here, the necessary modules and hooks for the component are imported, including React Native components, icons, TrackPlayer for audio playback, BackgroundTimer for background timer, and KeepAwake for keeping the device awake.

FiveMinutesScreen Function

The FiveMinutesScreen function is the main component that renders the five-minute timer screen. It uses local states to control the timer state, minutes, seconds, etc. It also uses various React hooks such as useEffect and useState to handle the timer logic and audio playback.

Playback Control Events and Functions

The component uses the useTrackPlayerEvents hook to handle playback track change events. It also defines functions to control the playback and pause of audio tracks.

Timer Logic

Inside the useEffect hook, the timer logic is implemented using BackgroundTimer to count time and update the timer state.

TenMinutesScreen.tsx


import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TrackPlayer, { State, usePlaybackState, Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import BackgroundTimer from 'react-native-background-timer';
import { setupPlayer, playbackService } from '../../musicPlayerServices';
import KeepAwake, { useKeepAwake,activateKeepAwake, deactivateKeepAwake  } from '@sayem314/react-native-keep-awake';

const TenMinutesScreen = () => {
  const [stopped, setStopped] = useState(true);
  const [paused, setPaused] = useState(true);
  const [minutes, setMinutes] = useState(10);
  const [seconds, setSeconds] = useState(0);
  const [temporizadorFinalizado, setTemporizadorFinalizado] = useState(false);
  const [track, setTrack] = useState<Track | null>();

    useTrackPlayerEvents([Event.PlaybackTrackChanged], async event => {
      switch (event.type) {
        case Event.PlaybackTrackChanged:
          const playingTrack = await TrackPlayer.getTrack(event.nextTrack)
          setTrack(playingTrack)
          break;
      }
    });

    const playbackState = usePlaybackState();

    const play = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
          if (playback === State.Stopped || playback === State.Ready) {
            await TrackPlayer.play()
          }
        }
    }

    const stop = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
            if (playback === State.Playing) {
                await TrackPlayer.pause(); 
                await TrackPlayer.seekTo(0);
            }
        }
    }

    const startTimer = async () => {
        if (temporizadorFinalizado) {
            setMinutes(10);
            setSeconds(0);
        }
        setStopped(false);
        setPaused(false);
        setTemporizadorFinalizado(false);
    };

    const pauseTimer = async () => {
        setPaused(true);
        setTemporizadorFinalizado(false);
    };

    const stopTimer = async () => {
        setStopped(true);
        setPaused(false);
        setMinutes(10);
        setSeconds(0);
        stop(playbackState);
        setTemporizadorFinalizado(true);
    };

    const resetTimer = async () => {
        setStopped(true);
        setPaused(true);
        setMinutes(10);
        setSeconds(0);
    };

  useEffect(() => {
        let interval: number;
        if (!stopped && !paused) {
            interval = BackgroundTimer.setInterval(() => {
                if (seconds > 0) {
                    setSeconds(seconds - 1);
                } else {
                    if (minutes === 0) {
                        BackgroundTimer.clearInterval(interval);
                        setStopped(true);
                        setTemporizadorFinalizado(true);
                        play(playbackState);                        
                    } else {
                        setMinutes(minutes - 1);
                        setSeconds(59);
                    }
                }
            }, 1000);
        }

        return () =>{
          if(interval){
            BackgroundTimer.clearInterval(interval);
          }
    };
   }, [stopped, paused, minutes, seconds]);

  return (
    <View style={styles.container}>
      <KeepAwake/>
      <Text style={styles.timerText}>
         {minutes<10 ? `0${minutes}`: minutes}:{seconds < 10 ? `0${seconds}` : seconds}
      </Text>
      <View style={styles.iconContainer}>
        <Icon name={paused ? 'play-box' : 'pause-octagon'} 
        size={100} 
        color="#192A56" 
        onPress={paused ? startTimer : pauseTimer} 
        />
        <Icon
            name={temporizadorFinalizado ? 'stop' : 'restore'}
            size={100}
            color="#192A56"
            onPress={temporizadorFinalizado ? stopTimer : resetTimer}
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#EA425C'
    },
    timerText: {
    fontSize: 100,
    fontWeight: 'bold',
    marginBottom: 10,
    color: '#192A56'
  },
  iconContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginTop: 20,
  },
});

export default TenMinutesScreen;

TwentyFiveMinutesScreen.tsx


import React, { useEffect, useState } from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import TrackPlayer, { State, usePlaybackState, Event, Track, useTrackPlayerEvents } from 'react-native-track-player';
import BackgroundTimer from 'react-native-background-timer';
import { setupPlayer, playbackService } from '../../musicPlayerServices';
import KeepAwake from '@sayem314/react-native-keep-awake';

const TwentyFiveMinutesScreen = () => {
  const [stopped, setStopped] = useState(true);
  const [paused, setPaused] = useState(true);
  const [minutes, setMinutes] = useState(25);
  const [seconds, setSeconds] = useState(0);
  const [temporizadorFinalizado, setTemporizadorFinalizado] = useState(false);
  const [track, setTrack] = useState<Track | null>();

    useTrackPlayerEvents([Event.PlaybackTrackChanged], async event => {
      switch (event.type) {
        case Event.PlaybackTrackChanged:
          const playingTrack = await TrackPlayer.getTrack(event.nextTrack)
          setTrack(playingTrack)
          break;
      }
    });    

    const playbackState = usePlaybackState();

    const play = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
          if (playback === State.Stopped || playback === State.Ready) {
            await TrackPlayer.play()
          }
        }
    }

    const stop = async (playback: State) => {
        const currentTrack = await TrackPlayer.getCurrentTrack()

        if (currentTrack !== null) {
            if (playback === State.Playing) {
                await TrackPlayer.pause(); 
                await TrackPlayer.seekTo(0);
            }
        }
    }

    const startTimer = async () => {
        if (temporizadorFinalizado) {
            setMinutes(25);
            setSeconds(0);
        }
        setStopped(false);
        setPaused(false);
        setTemporizadorFinalizado(false);
    };

    const pauseTimer = async () => {
        setPaused(true);
        setTemporizadorFinalizado(false);
    };

    const stopTimer = async () => {
        setStopped(true);
        setPaused(false);
        setMinutes(25);
        setSeconds(0);
        stop(playbackState);
        setTemporizadorFinalizado(true);
    };

    const resetTimer = async () => {
        setStopped(true);
        setPaused(true);
        setMinutes(25);
        setSeconds(0);
    };

  useEffect(() => {
        let interval: number;
        if (!stopped && !paused) {
            interval = BackgroundTimer.setInterval(() => {
                if (seconds > 0) {
                    setSeconds(seconds - 1);
                } else {
                    if (minutes === 0) {
                        BackgroundTimer.clearInterval(interval);
                        setStopped(true);
                        setTemporizadorFinalizado(true);
                        play(playbackState);
                    } else {
                        setMinutes(minutes - 1);
                        setSeconds(59);
                    }
                }
            }, 1000);
        }

        return () =>{
          if(interval){
            BackgroundTimer.clearInterval(interval);
          }
    };
   }, [stopped, paused, minutes, seconds]);

  return (
    <View style={styles.container}>
      <KeepAwake/>
      <Text style={styles.timerText}>
         {minutes<10 ? `0${minutes}`: minutes}:{seconds < 10 ? `0${seconds}` : seconds}
      </Text>
      <View style={styles.iconContainer}>
        <Icon name={paused ? 'play-box' : 'pause-octagon'} 
        size={100} 
        color="#192A56" 
        onPress={paused ? startTimer : pauseTimer} 
        />
        <Icon
            name={temporizadorFinalizado ? 'stop' : 'restore'}
            size={100}
            color="#192A56"
            onPress={temporizadorFinalizado ? stopTimer : resetTimer}
        />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: '#0ABDE3'
    },
    timerText: {
    fontSize: 100,
    fontWeight: 'bold',
    marginBottom: 10,
    color: '#192A56'
  },
  iconContainer: {
    flexDirection: 'row',
    justifyContent: 'space-around',
    marginTop: 20,
  },
});

export default TwentyFiveMinutesScreen;

App.tsx

import React, { useEffect, useState } from 'react';
import { ActivityIndicator, SafeAreaView, StatusBar, StyleSheet } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import FiveMinutesScreen from './components/FiveMinutesScreen';
import TenMinutesScreen from './components/TenMinutesScreen';
import TwentyFiveMinutesScreen from './components/TwentyFiveMinutesScreen';
import { setupPlayer, addTrack } from "../musicPlayerServices";


const Tab = createMaterialTopTabNavigator();

function App(): React.JSX.Element {
  const [activeTab, setActiveTab] = useState('Short Break');
   const [isPlayerReady, setIsPlayerReady] = useState(false);



   useEffect(() => {
    const initializePlayer = async () => {
      const isSetup = await setupPlayer();
      if (isSetup) {
        await addTrack();
      }
      setIsPlayerReady(isSetup);
    };

    initializePlayer();
 }, []);

  if (!isPlayerReady) {
    return (
      <SafeAreaView>
        <ActivityIndicator />
      </SafeAreaView>
    )
  }


  const getTabColor = (tabName: string) => {
    switch (tabName) {
      case 'Short Break':
        return '#F0DF87';
      case 'Pomodoro':
        return '#0ABDE3';
      case 'Long Break':
        return '#EA425C';
      default:
        return 'powderblue';
    }
  };

  return (
    <NavigationContainer>
      <StatusBar hidden />
      <Tab.Navigator
        screenOptions={{
          tabBarLabelStyle: { fontSize: 12, fontWeight: 'bold', color: '#2C3335' },
          tabBarStyle: { backgroundColor: 'powderblue' },
        }}
      >
        <Tab.Screen
          name="Short Break"
          component={FiveMinutesScreen}
          listeners={{
            focus: () => setActiveTab('Short Break'),
          }}
          options={{
            title: 'Short Break',
            tabBarIcon: ({ focused }) => (
              <Icon name={focused ? 'numeric-5-circle' : 'numeric-5-circle-outline'} size={25} color="#192A56" />
            ),
            tabBarStyle: { backgroundColor: getTabColor('Short Break') },
          }}
        />
        <Tab.Screen
          name="Pomodoro"
          component={TwentyFiveMinutesScreen}
          listeners={{
            focus: () => setActiveTab('Pomodoro'),
          }}
          options={{
            title: 'Pomodoro',
            tabBarIcon: ({ focused }) => (
              <Icon name={focused ? 'timer' : 'timer-outline'} size={25} color="#192A56" />
            ),
            tabBarStyle: { backgroundColor: getTabColor('Pomodoro') },
          }}
        />
        <Tab.Screen
          name="Long Break"
          component={TenMinutesScreen}
          listeners={{
            focus: () => setActiveTab('Long Break'),
          }}
          options={{
             title: 'Long Break',
            tabBarIcon: ({ focused }) => (
              <Icon name={focused ? 'numeric-10-circle' : 'numeric-10-circle-outline'} size={25} color="#192A56" />
            ),
            tabBarStyle: { backgroundColor: getTabColor('Long Break') },
          }}
        />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

const styles = StyleSheet.create({

});

export default App;

El código proporcionado es una aplicación de React que utiliza el componente NavigationContainer de @react-navigation/native para crear una interfaz de pestañas con tres pantallas diferentes: FiveMinutesScreen, TenMinutesScreen y TwentyFiveMinutesScreen. Aquí está el desglose paso a paso del código:

Importaciones

import React, { useEffect, useState } from 'react';
import { ActivityIndicator, SafeAreaView, StatusBar, StyleSheet } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import FiveMinutesScreen from './components/FiveMinutesScreen';
import TenMinutesScreen from './components/TenMinutesScreen';
import TwentyFiveMinutesScreen from './components/TwentyFiveMinutesScreen';
import { setupPlayer, addTrack } from "../musicPlayerServices";

Se importan los módulos y componentes necesarios para la aplicación, incluyendo componentes de React Native, iconos, NavigationContainer y createMaterialTopTabNavigator de @react-navigation/native, así como las pantallas de temporizador.

Función App

La función App es el componente principal que renderiza la aplicación. Utiliza el Tab.Navigator para crear las pestañas y asignar las pantallas correspondientes a cada pestaña. También inicializa el reproductor de música y muestra un indicador de actividad mientras se carga.

Inicialización del Reproductor de Música

Dentro del efecto useEffect, se inicializa el reproductor de música utilizando la función setupPlayer y se agrega una pista utilizando la función addTrack.

Lógica de las Pestañas

Cada pestaña tiene su propia pantalla correspondiente (FiveMinutesScreen, TenMinutesScreen, TwentyFiveMinutesScreen) y se configura con un ícono y un color de fondo basado en la pestaña activa.

The provided code is a React application that uses the NavigationContainer component from @react-navigation/native to create a tabbed interface with three different screens: FiveMinutesScreen, TenMinutesScreen, and TwentyFiveMinutesScreen. Here's the step-by-step breakdown of the code:

Imports

import React, { useEffect, useState } from 'react';
import { ActivityIndicator, SafeAreaView, StatusBar, StyleSheet } from 'react-native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import { NavigationContainer } from '@react-navigation/native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import FiveMinutesScreen from './components/FiveMinutesScreen';
import TenMinutesScreen from './components/TenMinutesScreen';
import TwentyFiveMinutesScreen from './components/TwentyFiveMinutesScreen';
import { setupPlayer, addTrack } from "../musicPlayerServices";

The necessary modules and components for the application are imported, including React Native components, icons, NavigationContainer, and createMaterialTopTabNavigator from @react-navigation/native, as well as the timer screens.

App Function

The App function is the main component that renders the application. It uses the Tab.Navigator to create the tabs and assign the corresponding screens to each tab. It also initializes the music player and shows an activity indicator while loading.

Music Player Initialization

Inside the useEffect effect, the music player is initialized using the setupPlayer function and a track is added using the addTrack function.

Tab Logic

Each tab has its own corresponding screen (FiveMinutesScreen, TenMinutesScreen, TwentyFiveMinutesScreen) and is configured with an icon and background color based on the active tab.

Video & Github

GitHub Repo