Skip to content

Commit

Permalink
Merge pull request #47 from lrtlt/feat/car-play-navigation
Browse files Browse the repository at this point in the history
Feat/car play navigation
  • Loading branch information
KestasVenslauskas authored Apr 25, 2024
2 parents 70abbd1 + 03ed028 commit 4986b95
Show file tree
Hide file tree
Showing 31 changed files with 735 additions and 290 deletions.
6 changes: 6 additions & 0 deletions app/api/Endpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,3 +163,9 @@ export const forecastGet = (cityCode: string) => {
export const liveFeedGet = (id: string | number, count: number, order: 'desc' | 'asc') => {
return `${BASE_URL}get-feed-items/${id}?count=${count}&order=${order}`;
};

export const carPlaylistNewestGet = () => 'https://www.lrt.lt/static/carplay/naujausi.json';

export const carPlaylistPopularGet = () => 'https://www.lrt.lt/static/carplay/pop.json';

export const carPlaylistRecommendedGet = () => 'https://www.lrt.lt/static/carplay/rekomenduoja.json';
7 changes: 7 additions & 0 deletions app/api/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,13 @@ export type ArticleEmbedTimelineType = {
src: string;
};

export type CarPlaylistItem = {
title: string;
content: string;
cover: string;
streamUrl: string;
};

export type ArticleContentDefault = {
article_id: number;
article_title: string;
Expand Down
10 changes: 10 additions & 0 deletions app/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import {
articleGet,
articlesGetByTag,
audiotekaGet,
carPlaylistNewestGet,
carPlaylistPopularGet,
carPlaylistRecommendedGet,
categoryGet,
channelGet,
forecastGet,
Expand All @@ -22,6 +25,7 @@ import {get, put} from './HttpClient';
import {
ArticleContentResponse,
AudiotekaResponse,
CarPlaylistItem,
CategoryArticlesResponse,
ChannelResponse,
DailyQuestionResponse,
Expand Down Expand Up @@ -93,3 +97,9 @@ export const setDailyQuestionVote = (questionId: number | string, choiceId: numb

export const fetchDailyQuestion = (questionId: number | string) =>
get<DailyQuestionResponse>(getDailyQuestion(questionId));

export const fetchCarNewestPlaylist = () => get<CarPlaylistItem[]>(carPlaylistNewestGet());

export const fetchCarPopularPlaylist = () => get<CarPlaylistItem[]>(carPlaylistPopularGet());

export const fetchCarRecommendedPlaylist = () => get<CarPlaylistItem[]>(carPlaylistRecommendedGet());
7 changes: 3 additions & 4 deletions app/car/CarPlayContext.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';

export type CarCategory = 'live' | 'newest';

export type PlayListItem = {
id: string | number;
text: string;
Expand All @@ -10,14 +12,11 @@ export type PlayListItem = {

export type CarPlayContextType = {
isConnected: boolean;
playlist: PlayListItem[];
setPlaylist: (playlist: PlayListItem[]) => void;
selectedCategory?: CarCategory;
};

const defaults: CarPlayContextType = {
isConnected: false,
playlist: [],
setPlaylist: () => {},
};

export const CarPlayContext = React.createContext<CarPlayContextType>(defaults);
16 changes: 3 additions & 13 deletions app/car/CarPlayProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
import React, {PropsWithChildren, useEffect, useMemo} from 'react';
import React, {PropsWithChildren, useMemo} from 'react';
import {CarPlayContext, CarPlayContextType} from './CarPlayContext';
import useCarPlayController from './useCarPlayController';
import useCarLiveChannels from './useCarLiveChannels';

const CarPlayProvider: React.FC<PropsWithChildren<{}>> = (props) => {
const {isConnected, setPlaylist, playlist} = useCarPlayController();
const {channels} = useCarLiveChannels(isConnected);

useEffect(() => {
if (channels.length > 0) {
setPlaylist(channels);
}
}, [channels]);
const {isConnected} = useCarPlayController();

const context: CarPlayContextType = useMemo(
() => ({
isConnected,
setPlaylist,
playlist: playlist,
}),
[isConnected, setPlaylist, playlist],
[isConnected],
);

return <CarPlayContext.Provider value={context}>{props.children}</CarPlayContext.Provider>;
Expand Down
44 changes: 0 additions & 44 deletions app/car/carPlayLiveTemplate.ts

This file was deleted.

12 changes: 12 additions & 0 deletions app/car/empty/createCarPlayEmptyTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {ListTemplate} from 'react-native-carplay';

export const carPlayEmptyTemplate = new ListTemplate({
id: 'lrt-empty-template',
backButtonHidden: true,
emptyViewSubtitleVariants: ['Prašome palaukti...'],
sections: [
{
items: [],
},
],
});
19 changes: 19 additions & 0 deletions app/car/live/createPlayLiveTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {ListTemplate} from 'react-native-carplay';

export const carPlayLiveTemplate = new ListTemplate({
title: 'Tiesiogiai',
id: 'lrt-list-template-live',
trailingNavigationBarButtons: [
{
id: 'reload',
type: 'text',
title: 'Atnaujinti',
},
],
sections: [
{
items: [],
},
],
backButtonHidden: true,
});
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
import {useSelector} from 'react-redux';
import {selectHomeChannels} from '../redux/selectors';
import {checkEqual} from '../util/LodashEqualityCheck';
import {selectHomeChannels} from '../../redux/selectors';
import {checkEqual} from '../../util/LodashEqualityCheck';
import {useEffect, useState} from 'react';
import {PlayListItem} from './CarPlayContext';
import {fetchStreamData} from '../components/videoComponent/fetchStreamData';
import useCancellablePromise from '../hooks/useCancellablePromise';
import {VIDEO_DEFAULT_BACKGROUND_IMAGE} from '../constants';
import {PlayListItem} from '../CarPlayContext';
import {fetchStreamData} from '../../components/videoComponent/fetchStreamData';
import useCancellablePromise from '../../hooks/useCancellablePromise';
import {VIDEO_DEFAULT_BACKGROUND_IMAGE} from '../../constants';

const useCarLiveChannels = (isActive: boolean) => {
const useCarLiveChannels = (isConnected: boolean) => {
const [channels, setChannels] = useState<PlayListItem[]>([]);
const [lastLoadTime, setLastLoadTime] = useState<number>(0);
const channelsData = useSelector(selectHomeChannels, checkEqual);

const cancellablePromise = useCancellablePromise();

useEffect(() => {
if (!isActive) {
if (!isConnected) {
return;
}

Expand All @@ -33,17 +34,18 @@ const useCarLiveChannels = (isActive: boolean) => {
const channels: PlayListItem[] = data.map((stream) => ({
id: stream.mediaId,
text: stream.channelTitle ?? stream.title,
// detailText: 'stream.title',
// detailText: stream.title,
imgUrl: stream.poster || VIDEO_DEFAULT_BACKGROUND_IMAGE,
streamUrl: stream.streamUri,
}));
setChannels(channels);
}
});
}, [channelsData, isActive]);
}, [channelsData, isConnected, lastLoadTime]);

return {
channels,
reload: () => setLastLoadTime(Date.now()),
};
};

Expand Down
61 changes: 61 additions & 0 deletions app/car/live/useCarLiveTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {useEffect, useState} from 'react';
import useCarLiveChannels from './useCarLiveChannels';
import {CarPlay, ListTemplate} from 'react-native-carplay';
import {carPlayLiveTemplate} from './createPlayLiveTemplate';
import {useMediaPlayer} from '../../components/videoComponent/context/useMediaPlayer';
import {MediaType} from '../../components/videoComponent/context/PlayerContext';
import {carPlayNowPlayingTemplate} from '../nowPlaying/createNowPlayingTemplate';

const useCarLiveTemplate = (isConnected: boolean) => {
const [template] = useState<ListTemplate>(carPlayLiveTemplate);
const {channels, reload} = useCarLiveChannels(isConnected);

const {setPlaylist} = useMediaPlayer();

useEffect(() => {
console.log('updating live template');
template.updateSections([
{
items: channels.map((item) => ({
text: item.text,
detailText: item.detailText,
imgUrl: item.imgUrl as any,
})),
},
]);
template.config.onItemSelect = async ({index}) => {
const item = channels[index];
setPlaylist([
{
uri: item.streamUrl,
mediaType: MediaType.VIDEO,
isLiveStream: true,
poster: item.imgUrl,
title: item.text,
},
]);
CarPlay.pushTemplate(carPlayNowPlayingTemplate, true);
};
return () => {
template.config.onItemSelect = undefined;
};
}, [channels]);

useEffect(() => {
if (template) {
template.config.onBarButtonPressed = async ({id}) => {
if (id === 'reload') {
console.log('reloading live template');
reload();
}
};
return () => {
template.config.onBarButtonPressed = undefined;
};
}
}, [template, reload]);

return template;
};

export default useCarLiveTemplate;
19 changes: 19 additions & 0 deletions app/car/newest/createPlayNewestTemplate.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {ListTemplate} from 'react-native-carplay';

export const carPlayNewestTemplate = new ListTemplate({
title: 'Naujausi',
id: 'lrt-list-template-newest',
trailingNavigationBarButtons: [
{
id: 'reload',
type: 'text',
title: 'Atnaujinti',
},
],
sections: [
{
items: [],
},
],
backButtonHidden: true,
});
42 changes: 42 additions & 0 deletions app/car/newest/useCarNewestPlaylist.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {useSelector} from 'react-redux';
import {selectHomeChannels} from '../../redux/selectors';
import {checkEqual} from '../../util/LodashEqualityCheck';
import {useEffect, useState} from 'react';
import {PlayListItem} from '../CarPlayContext';
import useCancellablePromise from '../../hooks/useCancellablePromise';
import {fetchCarNewestPlaylist} from '../../api';

const useCarPlayNewestPlaylist = (isConnected: boolean) => {
const [channels, setChannels] = useState<PlayListItem[]>([]);
const [lastLoadTime, setLastLoadTime] = useState<number>(0);
const channelsData = useSelector(selectHomeChannels, checkEqual);

const cancellablePromise = useCancellablePromise();

useEffect(() => {
if (!isConnected) {
return;
}
cancellablePromise(
fetchCarNewestPlaylist().then((data) => {
if (data?.length) {
const channels: PlayListItem[] = data.map((item) => ({
id: item.title,
text: item.title,
detailText: item.content,
imgUrl: item.cover,
streamUrl: item.streamUrl,
}));
setChannels(channels);
}
}),
);
}, [channelsData, isConnected, lastLoadTime]);

return {
channels,
reload: () => setLastLoadTime(Date.now()),
};
};

export default useCarPlayNewestPlaylist;
Loading

0 comments on commit 4986b95

Please sign in to comment.