feat(webui): show current cast device on top of the page

This commit is contained in:
Tsiry Sandratraina
2023-01-27 14:20:04 +03:00
parent d1df57dfc0
commit 42cc6e916c
26 changed files with 814 additions and 397 deletions

View File

@@ -256,7 +256,21 @@ impl Player for Chromecast {
if self.host.is_none() || self.port.is_none() {
return Err(Error::msg("No device connected"));
}
let (cast_device, _, _, _) = self.connect_without_host_verification(None)?;
let cast_device = match CastDevice::connect_without_host_verification(
self.host.as_ref().unwrap(),
self.port.unwrap(),
) {
Ok(cast_device) => cast_device,
Err(err) => panic!("Could not establish connection with Cast Device: {:?}", err),
};
cast_device
.connection
.connect(DEFAULT_DESTINATION_ID.to_string())
.unwrap();
cast_device.heartbeat.ping().unwrap();
let status = cast_device.receiver.get_status().unwrap();
let current_app = &CastDeviceApp::from_str(DEFAULT_APP_ID).unwrap();

View File

@@ -1121,6 +1121,39 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "connectToCastDevice",
"description": null,
"args": [
{
"name": "id",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Device",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "connectToDevice",
"description": null,
@@ -1310,6 +1343,18 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "disconnectFromCastDevice",
"description": null,
"args": [],
"type": {
"kind": "OBJECT",
"name": "Device",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "disconnectFromDevice",
"description": null,
@@ -2511,7 +2556,7 @@
"deprecationReason": null
},
{
"name": "connectedDevice",
"name": "connectedCastDevice",
"description": null,
"args": [],
"type": {
@@ -2527,13 +2572,17 @@
"deprecationReason": null
},
{
"name": "currentCastDevice",
"name": "connectedDevice",
"description": null,
"args": [],
"type": {
"kind": "OBJECT",
"name": "Device",
"ofType": null
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "OBJECT",
"name": "Device",
"ofType": null
}
},
"isDeprecated": false,
"deprecationReason": null

View File

@@ -15,6 +15,7 @@ import { Track } from "../../Types";
import { resourceUriResolver } from "../../ResourceUriResolver";
import { Device } from "../../Types/Device";
import { useTheme } from "@emotion/react";
import ListeningOn from "../ListeningOn";
const Container = styled.div`
display: flex;
@@ -166,8 +167,11 @@ export type AlbumDetailsProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const AlbumDetails: FC<AlbumDetailsProps> = (props) => {
@@ -180,6 +184,7 @@ const AlbumDetails: FC<AlbumDetailsProps> = (props) => {
onCreatePlaylist,
onAddTrackToPlaylist,
recentPlaylists,
currentCastDevice,
} = props;
const coverUrl = _.startsWith(album.cover, "https://")
? album.cover
@@ -187,71 +192,74 @@ const AlbumDetails: FC<AlbumDetailsProps> = (props) => {
const { cover } = useCover(coverUrl);
const theme = useTheme();
return (
<Container>
<Sidebar active="albums" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Album>
{cover && <AlbumCover src={cover} />}
{!cover && (
<NoAlbumCover>
<AlbumIcon />
</NoAlbumCover>
)}
<Metadata>
<MetadataContainer>
<Title>{album.title}</Title>
<Artist>{album.artist}</Artist>
<Tracks>{album.tracks.length} TRACKS</Tracks>
</MetadataContainer>
<Buttons>
<Button
onClick={() => onPlayAlbum(album.id, false)}
kind="primary"
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayAlbum(album.id, true)}
kind="secondary"
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
</Metadata>
</Album>
<TracksTable
tracks={album.tracks.map((track: any) => ({ ...track, cover }))}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
header={["#", "Title", "Artist", "Time"]}
maxHeight={"initial"}
onPlayTrack={(id, position) => onPlayAlbum(id, false, position)}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</Scrollable>
</MainContent>
</Content>
</Container>
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="albums" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Album>
{cover && <AlbumCover src={cover} />}
{!cover && (
<NoAlbumCover>
<AlbumIcon />
</NoAlbumCover>
)}
<Metadata>
<MetadataContainer>
<Title>{album.title}</Title>
<Artist>{album.artist}</Artist>
<Tracks>{album.tracks.length} TRACKS</Tracks>
</MetadataContainer>
<Buttons>
<Button
onClick={() => onPlayAlbum(album.id, false)}
kind="primary"
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayAlbum(album.id, true)}
kind="secondary"
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
</Metadata>
</Album>
<TracksTable
tracks={album.tracks.map((track: any) => ({ ...track, cover }))}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
header={["#", "Title", "Artist", "Time"]}
maxHeight={"initial"}
onPlayTrack={(id, position) => onPlayAlbum(id, false, position)}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</Scrollable>
</MainContent>
</Content>
</Container>
</>
);
};

View File

@@ -102,8 +102,11 @@ export type AlbumsProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
export type AlbumProps = {
@@ -128,10 +131,10 @@ const Album: FC<AlbumProps> = ({ onClick, album }) => {
};
const Albums: FC<AlbumsProps> = (props) => {
const { albums, onClickAlbum } = props;
const { albums, onClickAlbum, currentCastDevice } = props;
return (
<>
{false && <ListeningOn />}
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="albums" {...props} />
<Content>

View File

@@ -14,6 +14,7 @@ import AlbumIcon from "../Icons/AlbumCover";
import { Track } from "../../Types";
import { Device } from "../../Types/Device";
import { useTheme } from "@emotion/react";
import ListeningOn from "../ListeningOn";
const Container = styled.div`
display: flex;
@@ -185,8 +186,11 @@ export type ArtistDetailsProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const ArtistDetails: FC<ArtistDetailsProps> = (props) => {
@@ -200,89 +204,93 @@ const ArtistDetails: FC<ArtistDetailsProps> = (props) => {
onCreatePlaylist,
recentPlaylists,
onAddTrackToPlaylist,
currentCastDevice,
} = props;
const theme = useTheme();
return (
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Artist>{artist.name}</Artist>
<Buttons>
<Button
onClick={() => onPlayArtistTracks(artist.id, false)}
kind="primary"
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayArtistTracks(artist.id, true)}
kind="secondary"
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
<Tracks>
<TracksTable
tracks={tracks}
title={
<Row>
<Title>Tracks</Title>
<SeeMore>See all</SeeMore>
</Row>
}
maxHeight={"initial"}
onPlayTrack={(id, position) =>
onPlayArtistTracks(id, false, position)
}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</Tracks>
<Row>
<Title>Albums</Title>
<SeeMore>See all</SeeMore>
</Row>
<Grid gridColumns={[3, 4, 5]} gridMargins={[8, 16, 18]}>
{albums.map((item) => (
<Cell key={item.id}>
<Link to={`/albums/${item.id}`}>
{item.cover && <AlbumCover src={item.cover} />}
{!item.cover && (
<NoAlbumCover>
<AlbumIcon size={120} />
</NoAlbumCover>
)}
</Link>
<Link to={`/albums/${item.id}`}>
<AlbumTitle>{item.title}</AlbumTitle>
</Link>
<AlbumArtist>{item.artist}</AlbumArtist>
</Cell>
))}
</Grid>
</Scrollable>
</MainContent>
</Content>
</Container>
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Artist>{artist.name}</Artist>
<Buttons>
<Button
onClick={() => onPlayArtistTracks(artist.id, false)}
kind="primary"
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayArtistTracks(artist.id, true)}
kind="secondary"
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
<Tracks>
<TracksTable
tracks={tracks}
title={
<Row>
<Title>Tracks</Title>
<SeeMore>See all</SeeMore>
</Row>
}
maxHeight={"initial"}
onPlayTrack={(id, position) =>
onPlayArtistTracks(id, false, position)
}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</Tracks>
<Row>
<Title>Albums</Title>
<SeeMore>See all</SeeMore>
</Row>
<Grid gridColumns={[3, 4, 5]} gridMargins={[8, 16, 18]}>
{albums.map((item) => (
<Cell key={item.id}>
<Link to={`/albums/${item.id}`}>
{item.cover && <AlbumCover src={item.cover} />}
{!item.cover && (
<NoAlbumCover>
<AlbumIcon size={120} />
</NoAlbumCover>
)}
</Link>
<Link to={`/albums/${item.id}`}>
<AlbumTitle>{item.title}</AlbumTitle>
</Link>
<AlbumArtist>{item.artist}</AlbumArtist>
</Cell>
))}
</Grid>
</Scrollable>
</MainContent>
</Content>
</Container>
</>
);
};

View File

@@ -5,6 +5,7 @@ import { Track } from "../../Types";
import { Device } from "../../Types/Device";
import ControlBar from "../ControlBar";
import Artist from "../Icons/Artist";
import ListeningOn from "../ListeningOn";
import MainContent from "../MainContent";
import Sidebar from "../Sidebar";
@@ -93,43 +94,49 @@ export type ArtistsProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const Artists: FC<ArtistsProps> = (props) => {
const { onClickArtist, artists } = props;
const { onClickArtist, artists, currentCastDevice } = props;
return (
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<Scrollable>
<MainContent title="Artists" placeholder="Filter Artists">
<Wrapper>
<Grid gridColumns={[2, 3, 4]} gridMargins={[8, 16, 18]}>
{artists.map((item) => (
<Cell key={item.id}>
{item.cover && (
<ArtistCover
src={item.cover}
onClick={() => onClickArtist(item)}
/>
)}
{!item.cover && (
<NoArtistCover onClick={() => onClickArtist(item)}>
<Artist width={75} height={75} color="#a4a3a3" />
</NoArtistCover>
)}
<ArtistName>{item.name}</ArtistName>
</Cell>
))}
</Grid>
</Wrapper>
</MainContent>
</Scrollable>
</Content>
</Container>
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<Scrollable>
<MainContent title="Artists" placeholder="Filter Artists">
<Wrapper>
<Grid gridColumns={[2, 3, 4]} gridMargins={[8, 16, 18]}>
{artists.map((item) => (
<Cell key={item.id}>
{item.cover && (
<ArtistCover
src={item.cover}
onClick={() => onClickArtist(item)}
/>
)}
{!item.cover && (
<NoArtistCover onClick={() => onClickArtist(item)}>
<Artist width={75} height={75} color="#a4a3a3" />
</NoArtistCover>
)}
<ArtistName>{item.name}</ArtistName>
</Cell>
))}
</Grid>
</Wrapper>
</MainContent>
</Scrollable>
</Content>
</Container>
</>
);
};

View File

@@ -68,6 +68,7 @@ export type ControlBarProps = {
albumId: string;
};
castDevices: Device[];
currentCastDevice?: Device;
onPlay: () => void;
onPause: () => void;
onNext: () => void;
@@ -78,6 +79,8 @@ export type ControlBarProps = {
previousTracks?: Track[];
onPlayTrackAt: (position: number) => void;
onRemoveTrackAt: (position: number) => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const ControlBar: FC<ControlBarProps> = (props) => {
@@ -147,7 +150,7 @@ const ControlBar: FC<ControlBarProps> = (props) => {
<ButtonGroup>
<StatefulPopover
placement="bottom"
content={() => <DeviceList {...props} />}
content={({ close }) => <DeviceList {...props} close={close} />}
overrides={{
Body: {
style: {

View File

@@ -65,6 +65,22 @@ const IconWrapper = styled.div`
margin-right: 16px;
`;
const Disconnect = styled.button`
background-color: #000;
border: none;
color: #fff;
height: 21px;
border-radius: 12px;
font-family: "RockfordSansRegular";
font-size: 12px;
display: flex;
align-items: center;
justify-content: center;
width: 80px;
padding-bottom: 4px;
cursor: pointer;
`;
export type ArtworkProps = {
icon?: string;
color?: string;
@@ -94,10 +110,20 @@ const DeviceName = styled.div`
`;
export type DeviceListProps = {
currentCastDevice?: Device;
castDevices: Device[];
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
close: () => void;
};
const DeviceList: FC<DeviceListProps> = ({ castDevices }) => {
const DeviceList: FC<DeviceListProps> = ({
castDevices,
close,
connectToCastDevice,
disconnectFromCastDevice,
currentCastDevice,
}) => {
const theme = useTheme();
const colors: {
[key: string]: string;
@@ -106,46 +132,66 @@ const DeviceList: FC<DeviceListProps> = ({ castDevices }) => {
xbmc: "rgba(40, 203, 252, 0.082)",
airplay: "rgba(255, 0, 195, 0.063)",
};
const _onConnectToCastDevice = (deviceId: string) => {
connectToCastDevice(deviceId);
close();
};
const _onDisconnectFromCastDevice = () => {
disconnectFromCastDevice();
close();
};
return (
<Container>
<CurrentDeviceWrapper>
<IconWrapper>
<Laptop size={30} color={"#ab28fc"} />
</IconWrapper>
<div>
<div style={{ flex: 1 }}>
<CurrentDevice>Current device</CurrentDevice>
<CurrentDeviceName>Music Player</CurrentDeviceName>
<CurrentDeviceName>
{currentCastDevice ? currentCastDevice.name : "Music Player"}
</CurrentDeviceName>
</div>
{currentCastDevice && (
<Disconnect onClick={_onDisconnectFromCastDevice}>
disconnect
</Disconnect>
)}
</CurrentDeviceWrapper>
<Title>Select another output device</Title>
<List>
{castDevices.map((device) => (
<ListItem
key={device.id}
artwork={() => (
<Artwork icon={device.type} color={colors[device.type]} />
)}
overrides={{
Root: {
style: {
cursor: "pointer",
":hover": {
backgroundColor: theme.colors.hover,
<div onClick={() => _onConnectToCastDevice(device.id)}>
<ListItem
key={device.id}
artwork={() => (
<Artwork icon={device.type} color={colors[device.type]} />
)}
overrides={{
Root: {
style: {
cursor: "pointer",
":hover": {
backgroundColor: theme.colors.hover,
},
borderRadius: "5px",
},
borderRadius: "5px",
},
},
Content: {
style: {
borderBottom: "none",
Content: {
style: {
borderBottom: "none",
},
},
},
}}
>
<ListItemLabel>
<DeviceName>{device.name}</DeviceName>
</ListItemLabel>
</ListItem>
}}
>
<ListItemLabel>
<DeviceName>{device.name}</DeviceName>
</ListItemLabel>
</ListItem>
</div>
))}
</List>
</Container>

View File

@@ -14,6 +14,7 @@ import { Track } from "../../Types";
import { Folder as FolderIcon } from "@styled-icons/bootstrap";
import MovePlaylistsModal from "./MovePlaylistsModal";
import { Device } from "../../Types/Device";
import ListeningOn from "../ListeningOn";
const Container = styled.div`
display: flex;
@@ -194,8 +195,11 @@ export type FolderProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const Folder: FC<FolderProps> = (props) => {
@@ -206,53 +210,60 @@ const Folder: FC<FolderProps> = (props) => {
mainPlaylists,
folder,
onMovePlaylists,
currentCastDevice,
} = props;
const [isMovePlaylistsModalOpen, setIsMovePlaylistsModalOpen] =
useState(false);
return (
<Container>
<Sidebar active="artists" {...props} playlists={mainPlaylists} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
{folder?.playlists?.length > 0 && (
<Scrollable>
<MainContent title="Playlists" placeholder="Filter Playlists">
<Wrapper>
<Grid gridColumns={[2, 3, 4, 6]} gridMargins={[8, 16, 18]}>
{folder?.playlists.map((item: any) => (
<Cell key={item.id}>
<Playlist playlist={item} />
</Cell>
))}
</Grid>
</Wrapper>
</MainContent>
</Scrollable>
)}
{folder?.playlists?.length === 0 && (
<PlaceholderWrapper>
<FolderIcon size={100} color="rgb(70, 70, 70)" />
<Placeholder>
Start moving playlists to your folder.
</Placeholder>
<Button onClick={() => setIsMovePlaylistsModalOpen(true)}>
Move Playlists
</Button>
</PlaceholderWrapper>
)}
</Scrollable>
</MainContent>
</Content>
<MovePlaylistsModal
isOpen={isMovePlaylistsModalOpen}
onClose={() => setIsMovePlaylistsModalOpen(false)}
onMovePlaylists={onMovePlaylists}
playlists={playlists}
folderId={folder?.id}
/>
</Container>
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="artists" {...props} playlists={mainPlaylists} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
{folder?.playlists?.length > 0 && (
<Scrollable>
<MainContent title="Playlists" placeholder="Filter Playlists">
<Wrapper>
<Grid
gridColumns={[2, 3, 4, 6]}
gridMargins={[8, 16, 18]}
>
{folder?.playlists.map((item: any) => (
<Cell key={item.id}>
<Playlist playlist={item} />
</Cell>
))}
</Grid>
</Wrapper>
</MainContent>
</Scrollable>
)}
{folder?.playlists?.length === 0 && (
<PlaceholderWrapper>
<FolderIcon size={100} color="rgb(70, 70, 70)" />
<Placeholder>
Start moving playlists to your folder.
</Placeholder>
<Button onClick={() => setIsMovePlaylistsModalOpen(true)}>
Move Playlists
</Button>
</PlaceholderWrapper>
)}
</Scrollable>
</MainContent>
</Content>
<MovePlaylistsModal
isOpen={isMovePlaylistsModalOpen}
onClose={() => setIsMovePlaylistsModalOpen(false)}
onMovePlaylists={onMovePlaylists}
playlists={playlists}
folderId={folder?.id}
/>
</Container>
</>
);
};

View File

@@ -9,7 +9,7 @@ const Container = styled.div`
position: relative;
background: ${(props) => props.theme.colors.tooltip};
color: #ab28fc;
justify-content: flex-end;
justify-content: center;
align-items: center;
padding-right: 20px;
padding-top: 2px;
@@ -31,9 +31,10 @@ const IconWrapper = styled.div`
export type ListeningOnProps = {
icon?: "music-player" | "xbmc" | "airplay" | "chromecast";
deviceName?: string;
};
const ListeningOn: FC<ListeningOnProps> = ({ icon }) => {
const ListeningOn: FC<ListeningOnProps> = ({ icon, deviceName }) => {
return (
<Wrapper>
<Container>
@@ -47,7 +48,7 @@ const ListeningOn: FC<ListeningOnProps> = ({ icon }) => {
{icon === "chromecast" && <Chromecast size={15} color={"#ab28fc"} />}
</IconWrapper>
<div style={{ marginTop: -3, marginRight: 25 }}>
Listening on Salon TV
Listening on {deviceName}
</div>
</Container>
</Wrapper>

View File

@@ -16,6 +16,7 @@ import { useTimeFormat } from "../../Hooks/useFormat";
import { resourceUriResolver } from "../../ResourceUriResolver";
import { Device } from "../../Types/Device";
import { useTheme } from "@emotion/react";
import ListeningOn from "../ListeningOn";
const Container = styled.div`
display: flex;
@@ -155,8 +156,11 @@ export type PlaylistProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const Playlist: FC<PlaylistProps> = (props) => {
@@ -169,6 +173,7 @@ const Playlist: FC<PlaylistProps> = (props) => {
nowPlaying,
playlist,
recentPlaylists,
currentCastDevice,
} = props;
const { formatTime } = useTimeFormat();
const tracks =
@@ -186,82 +191,85 @@ const Playlist: FC<PlaylistProps> = (props) => {
})) || [];
const theme = useTheme();
return (
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Header>
<NoCover>
<PlaylistIcon
size={48}
color="#ab28fc"
style={{ marginRight: -38, marginTop: 38 }}
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="artists" {...props} />
<Content>
<ControlBar {...props} />
<MainContent displayHeader={false}>
<Scrollable>
<BackButton onClick={onBack}>
<div style={{ marginTop: 2 }}>
<ArrowBack color={theme.colors.text} />
</div>
</BackButton>
<Header>
<NoCover>
<PlaylistIcon
size={48}
color="#ab28fc"
style={{ marginRight: -38, marginTop: 38 }}
/>
</NoCover>
<PlaylistDetails>
<PlaylistDetailsWrapper>
<Title>{playlist.name}</Title>
</PlaylistDetailsWrapper>
<Buttons>
<Button
onClick={() => onPlayPlaylist(playlist.id, false)}
kind="primary"
disabled={!tracks.length}
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayPlaylist(playlist.id, true)}
kind="secondary"
disabled={!tracks.length}
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
</PlaylistDetails>
</Header>
{tracks.length === 0 && (
<Placeholder>
Start building your playlist with tracks by tapping on Add to
playlist in the option menu.
</Placeholder>
)}
{tracks.length > 0 && (
<TracksTable
tracks={tracks}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
header={["Title", "Artist", "Album", "Time"]}
maxHeight={"initial"}
onPlayTrack={(id, position) =>
onPlayPlaylist(id, false, position)
}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</NoCover>
<PlaylistDetails>
<PlaylistDetailsWrapper>
<Title>{playlist.name}</Title>
</PlaylistDetailsWrapper>
<Buttons>
<Button
onClick={() => onPlayPlaylist(playlist.id, false)}
kind="primary"
disabled={!tracks.length}
>
<Label>
<Icon>
<Play small color="#fff" />
</Icon>
<div style={{ marginLeft: 7 }}>Play</div>
</Label>
</Button>
<Separator />
<Button
onClick={() => onPlayPlaylist(playlist.id, true)}
kind="secondary"
disabled={!tracks.length}
>
<Label>
<Shuffle color="#ab28fc" />
<div style={{ marginLeft: 7 }}>Shuffle</div>
</Label>
</Button>
</Buttons>
</PlaylistDetails>
</Header>
{tracks.length === 0 && (
<Placeholder>
Start building your playlist with tracks by tapping on Add to
playlist in the option menu.
</Placeholder>
)}
{tracks.length > 0 && (
<TracksTable
tracks={tracks}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
header={["Title", "Artist", "Album", "Time"]}
maxHeight={"initial"}
onPlayTrack={(id, position) =>
onPlayPlaylist(id, false, position)
}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
)}
</Scrollable>
</MainContent>
</Content>
</Container>
)}
</Scrollable>
</MainContent>
</Content>
</Container>
</>
);
};

View File

@@ -9,6 +9,7 @@ import Albums from "./Albums";
import Artists from "./Artists";
import Playlists from "./Playlists";
import { Device } from "../../Types/Device";
import ListeningOn from "../ListeningOn";
const Container = styled.div`
display: flex;
@@ -66,59 +67,66 @@ export type SearchResultsProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const SearchResults: FC<SearchResultsProps> = (props) => {
const [activeKey, setActiveKey] = useState<React.Key>(0);
const { tracks, nowPlaying, onPlayTrack, onPlayNext } = props;
const { tracks, nowPlaying, onPlayTrack, onPlayNext, currentCastDevice } =
props;
return (
<Container>
<Sidebar active={""} {...props} />
<Content>
<ControlBar {...props} />
<div>
<Tabs
activeKey={activeKey}
onChange={({ activeKey }) => setActiveKey(activeKey)}
overrides={{
TabList: {
style: {
marginLeft: "26px",
marginRight: "26px",
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active={""} {...props} />
<Content>
<ControlBar {...props} />
<div>
<Tabs
activeKey={activeKey}
onChange={({ activeKey }) => setActiveKey(activeKey)}
overrides={{
TabList: {
style: {
marginLeft: "26px",
marginRight: "26px",
},
},
},
TabBorder: {
style: {
marginLeft: "26px",
marginRight: "26px",
TabBorder: {
style: {
marginLeft: "26px",
marginRight: "26px",
},
},
},
}}
>
<Tab title="Tracks">
<Results>
<Tracks {...props} />
</Results>
</Tab>
<Tab title="Albums">
<Results>
<Albums {...props} />
</Results>
</Tab>
<Tab title="Artists">
<Results>
<Artists {...props} />
</Results>
</Tab>
<Tab title="Playlists">
<Playlists />
</Tab>
</Tabs>
</div>
</Content>
</Container>
}}
>
<Tab title="Tracks">
<Results>
<Tracks {...props} />
</Results>
</Tab>
<Tab title="Albums">
<Results>
<Albums {...props} />
</Results>
</Tab>
<Tab title="Artists">
<Results>
<Artists {...props} />
</Results>
</Tab>
<Tab title="Playlists">
<Playlists />
</Tab>
</Tabs>
</div>
</Content>
</Container>
</>
);
};

View File

@@ -3,6 +3,7 @@ import { FC } from "react";
import { Track } from "../../Types";
import { Device } from "../../Types/Device";
import ControlBar from "../ControlBar";
import ListeningOn from "../ListeningOn";
import MainContent from "../MainContent";
import Sidebar from "../Sidebar";
import TracksTable from "../TracksTable";
@@ -54,8 +55,11 @@ export type TracksProps = {
devices: Device[];
castDevices: Device[];
currentDevice?: Device;
currentCastDevice?: Device;
connectToDevice: (deviceId: string) => void;
disconnectFromDevice: () => void;
connectToCastDevice: (deviceId: string) => void;
disconnectFromCastDevice: () => void;
};
const Tracks: FC<TracksProps> = (props) => {
@@ -67,26 +71,30 @@ const Tracks: FC<TracksProps> = (props) => {
onCreatePlaylist,
onAddTrackToPlaylist,
recentPlaylists,
currentCastDevice,
} = props;
return (
<Container>
<Sidebar active="tracks" {...props} />
<Content>
<ControlBar {...props} />
<MainContent title="Tracks">
<TracksTable
tracks={tracks}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
onPlayTrack={onPlayTrack}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</MainContent>
</Content>
</Container>
<>
{currentCastDevice && <ListeningOn deviceName={currentCastDevice.name} />}
<Container>
<Sidebar active="tracks" {...props} />
<Content>
<ControlBar {...props} />
<MainContent title="Tracks">
<TracksTable
tracks={tracks}
currentTrackId={nowPlaying.id}
isPlaying={nowPlaying.isPlaying}
onPlayTrack={onPlayTrack}
onPlayNext={onPlayNext}
onCreatePlaylist={onCreatePlaylist}
recentPlaylists={recentPlaylists}
onAddTrackToPlaylist={onAddTrackToPlaylist}
/>
</MainContent>
</Content>
</Container>
</>
);
};

View File

@@ -14,8 +14,11 @@ const AlbumDetailsPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const { data, loading, refetch } = useGetAlbumQuery({
variables: {
@@ -113,8 +116,11 @@ const AlbumDetailsPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -30,8 +30,11 @@ const AlbumsPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const albums = !loading && data ? data.albums : [];
const {
@@ -88,8 +91,11 @@ const AlbumsPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -43,8 +43,11 @@ const ArtistDetailsPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const artist = !loading && data ? data.artist : {};
const tracks =
@@ -130,8 +133,11 @@ const ArtistDetailsPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -27,8 +27,11 @@ const ArtistsPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const artists = !loading && data ? data.artists : [];
const {
@@ -84,8 +87,11 @@ const ArtistsPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -40,8 +40,11 @@ const FolderPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const {
folders,
@@ -95,8 +98,11 @@ const FolderPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -19,8 +19,11 @@ const PlaylistPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const { formatTime } = useTimeFormat();
const {
@@ -91,8 +94,11 @@ const PlaylistPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
);
};

View File

@@ -14,8 +14,11 @@ const SearchPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const {
play,
@@ -104,8 +107,11 @@ const SearchPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
</>
);

View File

@@ -32,8 +32,11 @@ const TracksPage = () => {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
} = useDevices();
const tracks = !loading && data ? data.tracks : [];
const {
@@ -104,8 +107,11 @@ const TracksPage = () => {
devices={devices}
castDevices={castDevices}
currentDevice={currentDevice}
currentCastDevice={currentCastDevice}
connectToDevice={(id) => connectToDevice({ variables: { id } })}
disconnectFromDevice={() => disconnectFromDevice()}
connectToCastDevice={(id) => connectToCastDevice({ variables: { id } })}
disconnectFromCastDevice={() => disconnectFromCastDevice()}
/>
</>
);

View File

@@ -15,3 +15,19 @@ export const DISCONNECT_FROM_DEVICE = gql`
}
}
`;
export const CONNECT_TO_CAST_DEVICE = gql`
mutation ConnectToCastDevice($id: ID!) {
connectToCastDevice(id: $id) {
id
}
}
`;
export const DISCONNECT_FROM_CAST_DEVICE = gql`
mutation DisconnectFromCastDevice {
disconnectFromCastDevice {
id
}
}
`;

View File

@@ -40,3 +40,16 @@ export const CONNECTED_DEVICE = gql`
}
}
`;
export const CONNECTED_CAST_DEVICE = gql`
query ConnectedCastDevice {
connectedCastDevice {
id
name
app
host
port
isConnected
}
}
`;

View File

@@ -19,6 +19,8 @@ export const ON_DEVICE_CONNECTED = gql`
onConnected {
id
name
service
app
}
}
`;
@@ -28,6 +30,8 @@ export const ON_DEVICE_DISCONNECTED = gql`
onDisconnected {
id
name
service
app
}
}
`;

View File

@@ -106,11 +106,13 @@ export type Mutation = {
addTrackToPlaylist: Playlist;
addTracks: Scalars['Boolean'];
clearTracklist: Scalars['Boolean'];
connectToCastDevice: Device;
connectToDevice: Device;
createFolder: Folder;
createPlaylist: Playlist;
deleteFolder: Folder;
deletePlaylist: Playlist;
disconnectFromCastDevice?: Maybe<Device>;
disconnectFromDevice?: Maybe<Device>;
movePlaylistToFolder: Folder;
movePlaylistsToFolder: Folder;
@@ -152,6 +154,11 @@ export type MutationAddTracksArgs = {
};
export type MutationConnectToCastDeviceArgs = {
id: Scalars['ID'];
};
export type MutationConnectToDeviceArgs = {
id: Scalars['ID'];
};
@@ -301,8 +308,8 @@ export type Query = {
albums: Array<Album>;
artist: Artist;
artists: Array<Artist>;
connectedCastDevice: Device;
connectedDevice: Device;
currentCastDevice?: Maybe<Device>;
currentlyPlayingSong: CurrentlyPlayingSong;
folder: Folder;
folders: Array<Folder>;
@@ -465,6 +472,18 @@ export type DisconnectFromDeviceMutationVariables = Exact<{ [key: string]: never
export type DisconnectFromDeviceMutation = { __typename?: 'Mutation', disconnectFromDevice?: { __typename?: 'Device', id: string } | null };
export type ConnectToCastDeviceMutationVariables = Exact<{
id: Scalars['ID'];
}>;
export type ConnectToCastDeviceMutation = { __typename?: 'Mutation', connectToCastDevice: { __typename?: 'Device', id: string } };
export type DisconnectFromCastDeviceMutationVariables = Exact<{ [key: string]: never; }>;
export type DisconnectFromCastDeviceMutation = { __typename?: 'Mutation', disconnectFromCastDevice?: { __typename?: 'Device', id: string } | null };
export type ListDevicesQueryVariables = Exact<{ [key: string]: never; }>;
@@ -480,6 +499,11 @@ export type ConnectedDeviceQueryVariables = Exact<{ [key: string]: never; }>;
export type ConnectedDeviceQuery = { __typename?: 'Query', connectedDevice: { __typename?: 'Device', id: string, name: string, app: string, host: string, port: number, isConnected: boolean } };
export type ConnectedCastDeviceQueryVariables = Exact<{ [key: string]: never; }>;
export type ConnectedCastDeviceQuery = { __typename?: 'Query', connectedCastDevice: { __typename?: 'Device', id: string, name: string, app: string, host: string, port: number, isConnected: boolean } };
export type OnNewDeviceSubscriptionVariables = Exact<{ [key: string]: never; }>;
@@ -488,12 +512,12 @@ export type OnNewDeviceSubscription = { __typename?: 'Subscription', onNewDevice
export type OnDeviceConnectedSubscriptionVariables = Exact<{ [key: string]: never; }>;
export type OnDeviceConnectedSubscription = { __typename?: 'Subscription', onConnected: { __typename?: 'ConnectedDevice', id: string, name: string } };
export type OnDeviceConnectedSubscription = { __typename?: 'Subscription', onConnected: { __typename?: 'ConnectedDevice', id: string, name: string, service: string, app: string } };
export type OnDeviceDisconnectedSubscriptionVariables = Exact<{ [key: string]: never; }>;
export type OnDeviceDisconnectedSubscription = { __typename?: 'Subscription', onDisconnected: { __typename?: 'DisconnectedDevice', id: string, name: string } };
export type OnDeviceDisconnectedSubscription = { __typename?: 'Subscription', onDisconnected: { __typename?: 'DisconnectedDevice', id: string, name: string, service: string, app: string } };
export type AlbumFragmentFragment = { __typename?: 'Album', id: string, title: string, artist: string, year?: number | null, cover?: string | null };
@@ -877,6 +901,71 @@ export function useDisconnectFromDeviceMutation(baseOptions?: Apollo.MutationHoo
export type DisconnectFromDeviceMutationHookResult = ReturnType<typeof useDisconnectFromDeviceMutation>;
export type DisconnectFromDeviceMutationResult = Apollo.MutationResult<DisconnectFromDeviceMutation>;
export type DisconnectFromDeviceMutationOptions = Apollo.BaseMutationOptions<DisconnectFromDeviceMutation, DisconnectFromDeviceMutationVariables>;
export const ConnectToCastDeviceDocument = gql`
mutation ConnectToCastDevice($id: ID!) {
connectToCastDevice(id: $id) {
id
}
}
`;
export type ConnectToCastDeviceMutationFn = Apollo.MutationFunction<ConnectToCastDeviceMutation, ConnectToCastDeviceMutationVariables>;
/**
* __useConnectToCastDeviceMutation__
*
* To run a mutation, you first call `useConnectToCastDeviceMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useConnectToCastDeviceMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [connectToCastDeviceMutation, { data, loading, error }] = useConnectToCastDeviceMutation({
* variables: {
* id: // value for 'id'
* },
* });
*/
export function useConnectToCastDeviceMutation(baseOptions?: Apollo.MutationHookOptions<ConnectToCastDeviceMutation, ConnectToCastDeviceMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<ConnectToCastDeviceMutation, ConnectToCastDeviceMutationVariables>(ConnectToCastDeviceDocument, options);
}
export type ConnectToCastDeviceMutationHookResult = ReturnType<typeof useConnectToCastDeviceMutation>;
export type ConnectToCastDeviceMutationResult = Apollo.MutationResult<ConnectToCastDeviceMutation>;
export type ConnectToCastDeviceMutationOptions = Apollo.BaseMutationOptions<ConnectToCastDeviceMutation, ConnectToCastDeviceMutationVariables>;
export const DisconnectFromCastDeviceDocument = gql`
mutation DisconnectFromCastDevice {
disconnectFromCastDevice {
id
}
}
`;
export type DisconnectFromCastDeviceMutationFn = Apollo.MutationFunction<DisconnectFromCastDeviceMutation, DisconnectFromCastDeviceMutationVariables>;
/**
* __useDisconnectFromCastDeviceMutation__
*
* To run a mutation, you first call `useDisconnectFromCastDeviceMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useDisconnectFromCastDeviceMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [disconnectFromCastDeviceMutation, { data, loading, error }] = useDisconnectFromCastDeviceMutation({
* variables: {
* },
* });
*/
export function useDisconnectFromCastDeviceMutation(baseOptions?: Apollo.MutationHookOptions<DisconnectFromCastDeviceMutation, DisconnectFromCastDeviceMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<DisconnectFromCastDeviceMutation, DisconnectFromCastDeviceMutationVariables>(DisconnectFromCastDeviceDocument, options);
}
export type DisconnectFromCastDeviceMutationHookResult = ReturnType<typeof useDisconnectFromCastDeviceMutation>;
export type DisconnectFromCastDeviceMutationResult = Apollo.MutationResult<DisconnectFromCastDeviceMutation>;
export type DisconnectFromCastDeviceMutationOptions = Apollo.BaseMutationOptions<DisconnectFromCastDeviceMutation, DisconnectFromCastDeviceMutationVariables>;
export const ListDevicesDocument = gql`
query ListDevices {
listDevices {
@@ -996,6 +1085,45 @@ export function useConnectedDeviceLazyQuery(baseOptions?: Apollo.LazyQueryHookOp
export type ConnectedDeviceQueryHookResult = ReturnType<typeof useConnectedDeviceQuery>;
export type ConnectedDeviceLazyQueryHookResult = ReturnType<typeof useConnectedDeviceLazyQuery>;
export type ConnectedDeviceQueryResult = Apollo.QueryResult<ConnectedDeviceQuery, ConnectedDeviceQueryVariables>;
export const ConnectedCastDeviceDocument = gql`
query ConnectedCastDevice {
connectedCastDevice {
id
name
app
host
port
isConnected
}
}
`;
/**
* __useConnectedCastDeviceQuery__
*
* To run a query within a React component, call `useConnectedCastDeviceQuery` and pass it any options that fit your needs.
* When your component renders, `useConnectedCastDeviceQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useConnectedCastDeviceQuery({
* variables: {
* },
* });
*/
export function useConnectedCastDeviceQuery(baseOptions?: Apollo.QueryHookOptions<ConnectedCastDeviceQuery, ConnectedCastDeviceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<ConnectedCastDeviceQuery, ConnectedCastDeviceQueryVariables>(ConnectedCastDeviceDocument, options);
}
export function useConnectedCastDeviceLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<ConnectedCastDeviceQuery, ConnectedCastDeviceQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<ConnectedCastDeviceQuery, ConnectedCastDeviceQueryVariables>(ConnectedCastDeviceDocument, options);
}
export type ConnectedCastDeviceQueryHookResult = ReturnType<typeof useConnectedCastDeviceQuery>;
export type ConnectedCastDeviceLazyQueryHookResult = ReturnType<typeof useConnectedCastDeviceLazyQuery>;
export type ConnectedCastDeviceQueryResult = Apollo.QueryResult<ConnectedCastDeviceQuery, ConnectedCastDeviceQueryVariables>;
export const OnNewDeviceDocument = gql`
subscription OnNewDevice {
onNewDevice {
@@ -1036,6 +1164,8 @@ export const OnDeviceConnectedDocument = gql`
onConnected {
id
name
service
app
}
}
`;
@@ -1066,6 +1196,8 @@ export const OnDeviceDisconnectedDocument = gql`
onDisconnected {
id
name
service
app
}
}
`;

View File

@@ -4,8 +4,11 @@ import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Device } from "../Types/Device";
import {
useConnectedCastDeviceQuery,
useConnectedDeviceQuery,
useConnectToCastDeviceMutation,
useConnectToDeviceMutation,
useDisconnectFromCastDeviceMutation,
useDisconnectFromDeviceMutation,
useListCastDevicesQuery,
useListDevicesQuery,
@@ -18,14 +21,19 @@ export const useDevices = () => {
const navigate = useNavigate();
const [currentDevice, setCurrentDevice] =
useState<Device | undefined>(undefined);
const [currentCastDevice, setCurrentCastDevice] =
useState<Device | undefined>(undefined);
const [devices, setDevices] = useState<Device[]>([]);
const [castDevices, setCastDevices] = useState<Device[]>([]);
const { data } = useOnNewDeviceSubscription();
const { data: listDevicesData } = useListDevicesQuery();
const { data: listCastDevicesData } = useListCastDevicesQuery();
const { data: connectedDeviceData, refetch } = useConnectedDeviceQuery();
const { data: connectedCastDeviceData } = useConnectedCastDeviceQuery();
const [connectToDevice] = useConnectToDeviceMutation();
const [disconnectFromDevice] = useDisconnectFromDeviceMutation();
const [connectToCastDevice] = useConnectToCastDeviceMutation();
const [disconnectFromCastDevice] = useDisconnectFromCastDeviceMutation();
const { data: deviceConnectedData } = useOnDeviceConnectedSubscription();
const { data: deviceDisconnectedData } =
useOnDeviceDisconnectedSubscription();
@@ -86,6 +94,15 @@ export const useDevices = () => {
enqueue({
message: `Connected to ${deviceConnectedData.onConnected.name}`,
});
if (deviceConnectedData.onConnected.app === "chromecast") {
setCurrentCastDevice({
id: deviceConnectedData.onConnected.id,
type: deviceConnectedData.onConnected.app,
name: deviceConnectedData.onConnected.name,
isConnected: true,
});
return;
}
refetch()
.then((result) => {
if (result.data?.connectedDevice) {
@@ -125,11 +142,24 @@ export const useDevices = () => {
});
}, [connectedDeviceData]);
useEffect(() => {
connectedCastDeviceData &&
setCurrentCastDevice({
id: connectedCastDeviceData.connectedCastDevice.id,
type: connectedCastDeviceData.connectedCastDevice.app,
name: connectedCastDeviceData.connectedCastDevice.name,
isConnected: connectedCastDeviceData.connectedCastDevice.isConnected,
});
}, [connectedCastDeviceData]);
return {
devices,
castDevices,
currentDevice,
currentCastDevice,
connectToDevice,
disconnectFromDevice,
connectToCastDevice,
disconnectFromCastDevice,
};
};