as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

Part 2: Final Code

Next Steps

Now that you've built your basic video app, here are some ways to continue your Vega learning journey:

  • Join our forums: Connect with other Vega developers, share your experiences, and get help with your projects in our developer community.

  • Check out other Sample Apps: Explore our collection of sample applications.

Final Code

Here is the final code for the lab:

Folder Structure

src/
├── components/
|   ├── index.ts
│   ├── Button.tsx
│   ├── Header.tsx
│   └── VideoCard.tsx
├── screens
|   ├── index.ts
│   ├── LandingScreen.tsx
|   ├── VideoDetailScreen.tsx
│   └── VideoPlaybackScreen.tsx
└── App.tsx

Components

index.ts

Copied to clipboard.


import Header from './Header';
import VideoCard from './VideoCard';
import Button from './Button';

export {
    Header,
    VideoCard,
    Button,
}

Header.tsx
VideoCard.tsx

Copied to clipboard.


import React, {useState} from 'react';
import {StyleSheet, Text, TouchableOpacity, Image, View} from 'react-native';

interface IProps {
  title: string;
  imgURL: string;
  description: string;
  pressFunction: Function;
}

const VideoCard = ({title, imgURL, description, pressFunction}: IProps) => {
  const [focused, setFocused] = useState(false);

  return (
    <TouchableOpacity
      style={[
        styles.videoCardContainer,
        focused ? styles.focused : styles.unfocused,
      ]}
      onPress={() => pressFunction()}
      onFocus={() => setFocused(true)}
      onBlur={() => setFocused(false)}>
      <Image style={styles.videoImage} source={{uri: imgURL}} />
      <View style={styles.videoTextContainer}>
        <Text style={styles.videoTitle}>{title}</Text>
        <Text style={styles.videoDescription}>{description}</Text>
      </View>
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  videoCardContainer: {
    height: 400,
    width: 550,
    margin: 10,
    borderRadius: 5,
  },
  unfocused: {
    borderWidth: 1,
    borderColor: 'white',
  },
  focused: {
    borderWidth: 5,
    borderColor: 'yellow',
  },
  videoTextContainer: {
    height: '25%',
    display: 'flex',
    justifyContent: 'space-around',
    padding: 10,
  },
  videoImage: {
    height: '75%',
  },
  videoTitle: {
    fontSize: 20,
    fontWeight: 'bold',
    color: 'white',
  },
  videoDescription: {
    color: 'white',
  },
});

export default VideoCard;

Button.tsx

Copied to clipboard.


import React, {useState} from 'react';
import {StyleSheet, TouchableOpacity, Text} from 'react-native';

export interface IProps {
  pressFunction: Function;
  buttonText: String;
}

const Button = ({pressFunction, buttonText}: IProps) => {
  const [focus, setFocused] = useState(false);

  return (
    <>
      <TouchableOpacity
        style={[styles.buttonContainer, focus && styles.focused]}
        onPress={() => pressFunction()}
        onFocus={() => setFocused(true)}
        onBlur={() => setFocused(false)}>
        <Text style={styles.buttonText}>{buttonText}</Text>
      </TouchableOpacity>
    </>
  );
};

const styles = StyleSheet.create({
  buttonContainer: {
    backgroundColor: '#FF9900',
    padding: 10,
    width: 150,
    display: 'flex',
    justifyContent: 'center',
    alignItems: 'center',
  },
  focused: {
    borderWidth: 3,
    borderColor: 'yellow',
    opacity: 0.8,
  },
  buttonText: {
    fontSize: 20,
  },
});

export default Button;

Screens

index.ts

Copied to clipboard.


import LandingScreen from './LandingScreen';
import VideoPlaybackScreen from './VideoPlaybackScreen';
import VideoDetailScreen from './VideoDetailScreen';

export {
    LandingScreen,
    VideoPlaybackScreen,
    VideoDetailScreen
}

LandingScreen.tsx

Copied to clipboard.


import React, {useState, useEffect} from 'react';
import {FlatList, StyleSheet, View, Text} from 'react-native';
import {Header, VideoCard} from '../components';
import {TVFocusGuideView} from '@amazon-devices/react-native-kepler';

interface IVideo {
  id: string;
  title: string;
  description: string;
  duration: number;
  thumbURL: string;
  imgURL: string;
  videoURL: string;
  categories: Array<string>;
  channel_id: number;
}

const LandingScreen = ({navigation}: any) => {
  const [islandVideos, setIslandVideos] = useState<IVideo[]>([]);
  const [underwaterVideos, setUnderwaterVideos] = useState<IVideo[]>([]);

  const url = 'https://d2ob7xfxpe6plv.cloudfront.net/TestData.json';

  const getAllVideos = () => {
    fetch(url)
      .then((response) => response.json())
      .then((data) => {
        // Filter videos for each category
        const islands = data.testData.filter(
          (video: IVideo) =>
            video.categories && video.categories.includes('Costa Rica Islands'),
        );

        const underwater = data.testData.filter(
          (video: IVideo) =>
            video.categories &&
            video.categories.includes('Costa Rica Underwater'),
        );

        setIslandVideos(islands);
        setUnderwaterVideos(underwater);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  useEffect(() => {
    getAllVideos();
  }, []);

  return (
    <>
      <Header />
      <TVFocusGuideView autoFocus={true}>
        <Text style={styles.categoryTitle}>Costa Rica Islands</Text>
        <FlatList
          style={styles.flatList}
          horizontal
          data={islandVideos}
          renderItem={({item}) => (
            <View style={styles.itemContainer}>
              <VideoCard
                title={item.title}
                description={
                  item.description.split(' ').slice(0, 20).join(' ') + '...'
                }
                imgURL={item.imgURL}
                pressFunction={() =>
                  navigation.navigate('VideoDetailScreen', {video: item})
                }
              />
            </View>
          )}
        />
      </TVFocusGuideView>
      <TVFocusGuideView autoFocus={true}>
        <Text style={styles.categoryTitle}>Costa Rica Underwater</Text>
        <FlatList
          style={styles.flatList}
          horizontal
          data={underwaterVideos}
          renderItem={({item}) => (
            <View style={styles.itemContainer}>
              <VideoCard
                title={item.title}
                description={
                  item.description.split(' ').slice(0, 20).join(' ') + '...'
                }
                imgURL={item.imgURL}
                pressFunction={() =>
                  navigation.navigate('VideoDetailScreen', {video: item})
                }
              />
            </View>
          )}
        />
      </TVFocusGuideView>
    </>
  );
};

const styles = StyleSheet.create({
  flatList: {
    padding: 10,
  },
  itemContainer: {
    margin: 10,
  },
  categoryTitle: {
    fontSize: 24,
    fontWeight: 'bold',
    color: 'white',
    marginLeft: 30,
  },
});

export default LandingScreen;

VideoDetailScreen.tsx

Copied to clipboard.


import React from 'react';
import {ImageBackground, Text, View, StyleSheet} from 'react-native';
import {Button} from '../components';

const VideoDetailScreen = ({navigation, route}: any) => {
  const video = route.params.video;

  return (
    <ImageBackground
      source={{uri: video.imgURL}}
      imageStyle={styles.image}
      style={styles.screenContainer}>
      <Text style={styles.videoTitle}>{video.title}</Text>
      <Text style={styles.videoDescription}>{video.description}</Text>
      <View style={styles.buttonContainer}>
        <Button
          buttonText="Watch Now"
          pressFunction={() =>
            navigation.navigate('VideoPlaybackScreen', {
              videoURL: video.videoURL,
            })
          }
        />
        <Button buttonText="Back" pressFunction={() => navigation.goBack()} />
      </View>
    </ImageBackground>
  );
};

const styles = StyleSheet.create({
  image: {
    opacity: 0.2,
  },
  screenContainer: {
    display: 'flex',
    height: '100%',
    justifyContent: 'center',
  },
  videoTitle: {
    fontSize: 50,
    color: 'white',
    fontWeight: '700',
    margin: 30,
  },
  videoDescription: {
    color: 'white',
    fontSize: 30,
    margin: 30,
  },
  buttonContainer: {
    display: 'flex',
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginLeft: 30,
    width: '18%',
  },
});

export default VideoDetailScreen;

VideoPlaybackScreen.tsx

Copied to clipboard.


import React from 'react';
import {View, StyleSheet, Text} from 'react-native';
import {Button} from '../components';

const VideoPlaybackScreen = ({navigation, route}: any) => {
  return (
    <View style={styles.playerContainer}>
      <Text style={styles.playerPlaceholder}>{route.params.videoURL}</Text>
      <View style={styles.buttonContainer}>
        <Button buttonText="Back" pressFunction={() => navigation.goBack()} />
      </View>
    </View>
  );
};

const styles = StyleSheet.create({
  playerContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  buttonContainer: {
    width: 100,
    position: 'absolute',
    top: 10,
    left: 10,
  },
  playerPlaceholder: {
    color: 'white',
    fontSize: 30,
  },
});

export default VideoPlaybackScreen;

App.tsx

Copied to clipboard.


import * as React from 'react';
import { NavigationContainer, DefaultTheme } from '@amazon-devices/react-navigation__native';
import { createStackNavigator } from '@amazon-devices/react-navigation__stack';
import { LandingScreen, VideoDetailScreen, VideoPlaybackScreen } from './screens';

export const App = () => {
  const Stack = createStackNavigator();

  const AppTheme = {
    ...DefaultTheme,
    colors: {
        ...DefaultTheme.colors,
        background: "#232F3E",
        text: "white",
    },
  };

  return (
    <NavigationContainer theme={AppTheme}>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        <Stack.Screen name='LandingScreen' component={LandingScreen}/>
        <Stack.Screen name='VideoDetailScreen' component={VideoDetailScreen}/>
        <Stack.Screen name='VideoPlaybackScreen' component={VideoPlaybackScreen}/>
      </Stack.Navigator>
    </NavigationContainer>
  );
}