mirror of
https://github.com/Qortal/q-tube.git
synced 2025-02-14 19:25:52 +00:00
Subscriptions to channels added
Filter added that removes characters that Operating Systems don't allow in filenames when saving file VideoList-styles.tsx uses Radio button instead of Checkbox for main page video/playlist filter Video player has aspect ratio of 16 / 9, doesn't put controls over video, and removes controls if mouse exits video when in fullscreen (but only when playing for some reason) Created new redux slice called settingsSlice.ts. It is used to store settings that are saved to disk automatically Home page remembers whether you were looking for videos or playlists VideoPlayer.tsx remembers last playbackRate when video is loaded, this is persistent. Videos reload when clicking on the videos or playlists filter type (user doesn't have to click Search button after changing the type) <FiltersTitle> for type and categories have been removed due to being redundant and confusing.
This commit is contained in:
parent
bc096b5a66
commit
7e502a3a47
@ -2,7 +2,7 @@ import { Button, ButtonProps } from "@mui/material";
|
|||||||
import { MouseEvent, useEffect, useState } from "react";
|
import { MouseEvent, useEffect, useState } from "react";
|
||||||
import { useDispatch, useSelector } from "react-redux";
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
import { RootState } from "../../state/store.ts";
|
import { RootState } from "../../state/store.ts";
|
||||||
import { subscribe, unSubscribe } from "../../state/features/videoSlice.ts";
|
import { subscribe, unSubscribe } from "../../state/features/persistSlice.ts";
|
||||||
|
|
||||||
interface SubscribeButtonProps extends ButtonProps {
|
interface SubscribeButtonProps extends ButtonProps {
|
||||||
name: string;
|
name: string;
|
||||||
@ -10,13 +10,13 @@ interface SubscribeButtonProps extends ButtonProps {
|
|||||||
|
|
||||||
export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => {
|
export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => {
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const select = useSelector((state: RootState) => {
|
const persistSelector = useSelector((state: RootState) => {
|
||||||
return state.video;
|
return state.persist;
|
||||||
});
|
});
|
||||||
const [isSubscribed, setIsSubscribed] = useState<boolean>(false);
|
const [isSubscribed, setIsSubscribed] = useState<boolean>(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsSubscribed(select.subscriptionList.includes(name));
|
setIsSubscribed(persistSelector.subscriptionList.includes(name));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const subscribeToRedux = () => {
|
const subscribeToRedux = () => {
|
||||||
@ -37,7 +37,6 @@ export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => {
|
|||||||
const verticalPadding = "3px";
|
const verticalPadding = "3px";
|
||||||
const horizontalPadding = "8px";
|
const horizontalPadding = "8px";
|
||||||
const buttonStyle = {
|
const buttonStyle = {
|
||||||
...props.sx,
|
|
||||||
fontSize: "15px",
|
fontSize: "15px",
|
||||||
fontWeight: "700",
|
fontWeight: "700",
|
||||||
paddingTop: verticalPadding,
|
paddingTop: verticalPadding,
|
||||||
@ -45,7 +44,8 @@ export const SubscribeButton = ({ name, ...props }: SubscribeButtonProps) => {
|
|||||||
paddingLeft: horizontalPadding,
|
paddingLeft: horizontalPadding,
|
||||||
paddingRight: horizontalPadding,
|
paddingRight: horizontalPadding,
|
||||||
borderRadius: 28,
|
borderRadius: 28,
|
||||||
height: "40px",
|
height: "45px",
|
||||||
|
...props.sx,
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
|
@ -26,6 +26,7 @@ import {
|
|||||||
VideoElement,
|
VideoElement,
|
||||||
} from "./VideoPlayer-styles.ts";
|
} from "./VideoPlayer-styles.ts";
|
||||||
import CSS from "csstype";
|
import CSS from "csstype";
|
||||||
|
import { setReduxPlaybackRate } from "../../../state/features/persistSlice.ts";
|
||||||
|
|
||||||
interface VideoPlayerProps {
|
interface VideoPlayerProps {
|
||||||
src?: string;
|
src?: string;
|
||||||
@ -59,6 +60,8 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
autoPlay,
|
autoPlay,
|
||||||
style = {},
|
style = {},
|
||||||
}) => {
|
}) => {
|
||||||
|
const videoSelector = useSelector((state: RootState) => state.video);
|
||||||
|
const persistSelector = useSelector((state: RootState) => state.persist);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const videoRef = useRef<HTMLVideoElement | null>(null);
|
const videoRef = useRef<HTMLVideoElement | null>(null);
|
||||||
const [playing, setPlaying] = useState(false);
|
const [playing, setPlaying] = useState(false);
|
||||||
@ -70,14 +73,15 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
const [canPlay, setCanPlay] = useState(false);
|
const [canPlay, setCanPlay] = useState(false);
|
||||||
const [startPlay, setStartPlay] = useState(false);
|
const [startPlay, setStartPlay] = useState(false);
|
||||||
const [isMobileView, setIsMobileView] = useState(false);
|
const [isMobileView, setIsMobileView] = useState(false);
|
||||||
const [playbackRate, setPlaybackRate] = useState(1);
|
const [playbackRate, setPlaybackRate] = useState(
|
||||||
|
persistSelector.playbackRate
|
||||||
|
);
|
||||||
const [anchorEl, setAnchorEl] = useState(null);
|
const [anchorEl, setAnchorEl] = useState(null);
|
||||||
const [showControlsFullScreen, setShowControlsFullScreen] =
|
const [showControlsFullScreen, setShowControlsFullScreen] =
|
||||||
useState<boolean>(true);
|
useState<boolean>(true);
|
||||||
const videoPlaying = useSelector(
|
const videoPlaying = useSelector(
|
||||||
(state: RootState) => state.global.videoPlaying
|
(state: RootState) => state.global.videoPlaying
|
||||||
);
|
);
|
||||||
const settingsState = useSelector((state: RootState) => state.settings);
|
|
||||||
const { downloads } = useSelector((state: RootState) => state.global);
|
const { downloads } = useSelector((state: RootState) => state.global);
|
||||||
|
|
||||||
const reDownload = useRef<boolean>(false);
|
const reDownload = useRef<boolean>(false);
|
||||||
@ -109,8 +113,10 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
const updatePlaybackRate = (newSpeed: number) => {
|
const updatePlaybackRate = (newSpeed: number) => {
|
||||||
if (videoRef.current) {
|
if (videoRef.current) {
|
||||||
if (newSpeed > maxSpeed || newSpeed < minSpeed) newSpeed = minSpeed;
|
if (newSpeed > maxSpeed || newSpeed < minSpeed) newSpeed = minSpeed;
|
||||||
videoRef.current.playbackRate = newSpeed;
|
|
||||||
|
videoRef.current.playbackRate = playbackRate;
|
||||||
setPlaybackRate(newSpeed);
|
setPlaybackRate(newSpeed);
|
||||||
|
dispatch(setReduxPlaybackRate(newSpeed));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -282,6 +288,7 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
const handleCanPlay = () => {
|
const handleCanPlay = () => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setCanPlay(true);
|
setCanPlay(true);
|
||||||
|
updatePlaybackRate(playbackRate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const getSrc = React.useCallback(async () => {
|
const getSrc = React.useCallback(async () => {
|
||||||
@ -767,18 +774,16 @@ export const VideoPlayer: React.FC<VideoPlayerProps> = ({
|
|||||||
onCanPlay={handleCanPlay}
|
onCanPlay={handleCanPlay}
|
||||||
onMouseEnter={e => {
|
onMouseEnter={e => {
|
||||||
setShowControlsFullScreen(true);
|
setShowControlsFullScreen(true);
|
||||||
console.log("entering video, fullscreen is: ", isFullscreen);
|
|
||||||
}}
|
}}
|
||||||
onMouseLeave={e => {
|
onMouseLeave={e => {
|
||||||
setShowControlsFullScreen(false);
|
setShowControlsFullScreen(false);
|
||||||
console.log("leaving video, fullscreen is: ", isFullscreen);
|
|
||||||
}}
|
}}
|
||||||
preload="metadata"
|
preload="metadata"
|
||||||
style={
|
style={
|
||||||
startPlay
|
startPlay
|
||||||
? {
|
? {
|
||||||
...customStyle,
|
...customStyle,
|
||||||
objectFit: settingsState.stretchVideoSetting,
|
objectFit: persistSelector.stretchVideoSetting,
|
||||||
height: "calc(100% - 80px)",
|
height: "calc(100% - 80px)",
|
||||||
}
|
}
|
||||||
: { ...customStyle, height: "100%" }
|
: { ...customStyle, height: "100%" }
|
||||||
|
@ -37,7 +37,7 @@ export const useFetchVideos = () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const subscriptions = useSelector(
|
const subscriptions = useSelector(
|
||||||
(state: RootState) => state.video.subscriptionList
|
(state: RootState) => state.persist.subscriptionList
|
||||||
);
|
);
|
||||||
|
|
||||||
const checkAndUpdateVideo = React.useCallback(
|
const checkAndUpdateVideo = React.useCallback(
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { RootState } from "../../state/store";
|
import { RootState } from "../../state/store";
|
||||||
import {
|
import {
|
||||||
Avatar,
|
|
||||||
Box,
|
Box,
|
||||||
Button,
|
Button,
|
||||||
FormControl,
|
FormControl,
|
||||||
@ -16,69 +14,38 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
SelectChangeEvent,
|
SelectChangeEvent,
|
||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import { useFetchVideos } from "../../hooks/useFetchVideos";
|
import { useFetchVideos } from "../../hooks/useFetchVideos";
|
||||||
import LazyLoad from "../../components/common/LazyLoad";
|
import LazyLoad from "../../components/common/LazyLoad";
|
||||||
import {
|
import {
|
||||||
BlockIconContainer,
|
|
||||||
BottomParent,
|
|
||||||
FilterSelect,
|
|
||||||
FiltersCheckbox,
|
|
||||||
FiltersCol,
|
FiltersCol,
|
||||||
FiltersContainer,
|
FiltersContainer,
|
||||||
FiltersRow,
|
FiltersRow,
|
||||||
FiltersSubContainer,
|
FiltersSubContainer,
|
||||||
FiltersTitle,
|
|
||||||
IconsBox,
|
|
||||||
NameContainer,
|
|
||||||
VideoCardCol,
|
|
||||||
ProductManagerRow,
|
ProductManagerRow,
|
||||||
VideoCardContainer,
|
|
||||||
VideoCard,
|
|
||||||
VideoCardName,
|
|
||||||
VideoCardTitle,
|
|
||||||
VideoContainer,
|
|
||||||
VideoUploadDate,
|
|
||||||
FiltersRadioButton,
|
FiltersRadioButton,
|
||||||
} from "./VideoList-styles";
|
} from "./VideoList-styles";
|
||||||
import ResponsiveImage from "../../components/ResponsiveImage";
|
import { SubtitleContainer } from "./Home-styles";
|
||||||
import { formatDate, formatTimestampSeconds } from "../../utils/time";
|
|
||||||
import { Subtitle, SubtitleContainer } from "./Home-styles";
|
|
||||||
import { ExpandMoreSVG } from "../../assets/svgs/ExpandMoreSVG";
|
|
||||||
import {
|
import {
|
||||||
addVideos,
|
|
||||||
blockUser,
|
|
||||||
changeFilterType,
|
|
||||||
changeSelectedCategoryVideos,
|
changeSelectedCategoryVideos,
|
||||||
changeSelectedSubCategoryVideos,
|
changeSelectedSubCategoryVideos,
|
||||||
changefilterName,
|
changefilterName,
|
||||||
changefilterSearch,
|
changefilterSearch,
|
||||||
clearVideoList,
|
|
||||||
setEditPlaylist,
|
|
||||||
setEditVideo,
|
|
||||||
} from "../../state/features/videoSlice";
|
} from "../../state/features/videoSlice";
|
||||||
|
import { changeFilterType } from "../../state/features/persistSlice.ts";
|
||||||
import { categories, subCategories } from "../../constants/Categories.ts";
|
import { categories, subCategories } from "../../constants/Categories.ts";
|
||||||
import { Playlists } from "../../components/Playlists/Playlists";
|
|
||||||
import { PlaylistSVG } from "../../assets/svgs/PlaylistSVG";
|
|
||||||
import BlockIcon from "@mui/icons-material/Block";
|
|
||||||
import EditIcon from "@mui/icons-material/Edit";
|
|
||||||
import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx";
|
import { ListSuperLikeContainer } from "../../components/common/ListSuperLikes/ListSuperLikeContainer.tsx";
|
||||||
import { VideoCardImageContainer } from "./VideoCardImageContainer";
|
|
||||||
import { SubscribeButton } from "../../components/common/SubscribeButton.tsx";
|
|
||||||
import { TabContext, TabList, TabPanel } from "@mui/lab";
|
import { TabContext, TabList, TabPanel } from "@mui/lab";
|
||||||
import VideoList from "./VideoList.tsx";
|
import VideoList from "./VideoList.tsx";
|
||||||
import { allTabValue, subscriptionTabValue } from "../../constants/Misc.ts";
|
import { allTabValue, subscriptionTabValue } from "../../constants/Misc.ts";
|
||||||
import { setHomePageSelectedTab } from "../../state/features/settingsSlice.ts";
|
import { setHomePageSelectedTab } from "../../state/features/persistSlice.ts";
|
||||||
|
|
||||||
interface HomeProps {
|
interface HomeProps {
|
||||||
mode?: string;
|
mode?: string;
|
||||||
}
|
}
|
||||||
export const Home = ({ mode }: HomeProps) => {
|
export const Home = ({ mode }: HomeProps) => {
|
||||||
const theme = useTheme();
|
|
||||||
const prevVal = useRef("");
|
const prevVal = useRef("");
|
||||||
const isFiltering = useSelector(
|
const isFiltering = useSelector(
|
||||||
(state: RootState) => state.video.isFiltering
|
(state: RootState) => state.video.isFiltering
|
||||||
@ -86,34 +53,43 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
const filterValue = useSelector(
|
const filterValue = useSelector(
|
||||||
(state: RootState) => state.video.filterValue
|
(state: RootState) => state.video.filterValue
|
||||||
);
|
);
|
||||||
|
const persistSelector = useSelector((state: RootState) => state.persist);
|
||||||
|
const filterType = useSelector(
|
||||||
|
(state: RootState) => state.persist.filterType
|
||||||
|
);
|
||||||
|
const filterSearch = useSelector(
|
||||||
|
(state: RootState) => state.video.filterSearch
|
||||||
|
);
|
||||||
|
const filterName = useSelector((state: RootState) => state.video.filterName);
|
||||||
|
const selectedCategoryVideos = useSelector(
|
||||||
|
(state: RootState) => state.video.selectedCategoryVideos
|
||||||
|
);
|
||||||
|
|
||||||
|
const { videos: globalVideos } = useSelector(
|
||||||
|
(state: RootState) => state.video
|
||||||
|
);
|
||||||
|
|
||||||
const settingsState = useSelector((state: RootState) => state.settings);
|
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [tabValue, setTabValue] = useState<string>(settingsState.selectedTab);
|
const [tabValue, setTabValue] = useState<string>(persistSelector.selectedTab);
|
||||||
|
|
||||||
const tabFontSize = "20px";
|
const tabFontSize = "20px";
|
||||||
const filterType = useSelector((state: RootState) => state.video.filterType);
|
|
||||||
|
|
||||||
const setFilterType = payload => {
|
const setFilterType = payload => {
|
||||||
dispatch(changeFilterType(payload));
|
dispatch(changeFilterType(payload));
|
||||||
};
|
};
|
||||||
const filterSearch = useSelector(
|
|
||||||
(state: RootState) => state.video.filterSearch
|
|
||||||
);
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Makes displayed videos reload when switching filter type. Removes need to click Search button after changing type
|
||||||
|
getVideosHandler(true);
|
||||||
|
}, [filterType]);
|
||||||
const setFilterSearch = payload => {
|
const setFilterSearch = payload => {
|
||||||
dispatch(changefilterSearch(payload));
|
dispatch(changefilterSearch(payload));
|
||||||
};
|
};
|
||||||
const filterName = useSelector((state: RootState) => state.video.filterName);
|
|
||||||
|
|
||||||
const setFilterName = payload => {
|
const setFilterName = payload => {
|
||||||
dispatch(changefilterName(payload));
|
dispatch(changefilterName(payload));
|
||||||
};
|
};
|
||||||
|
|
||||||
const selectedCategoryVideos = useSelector(
|
|
||||||
(state: RootState) => state.video.selectedCategoryVideos
|
|
||||||
);
|
|
||||||
|
|
||||||
const setSelectedCategoryVideos = payload => {
|
const setSelectedCategoryVideos = payload => {
|
||||||
dispatch(changeSelectedCategoryVideos(payload));
|
dispatch(changeSelectedCategoryVideos(payload));
|
||||||
};
|
};
|
||||||
@ -133,19 +109,8 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
const isFilterMode = useRef(false);
|
const isFilterMode = useRef(false);
|
||||||
const firstFetch = useRef(false);
|
const firstFetch = useRef(false);
|
||||||
const afterFetch = useRef(false);
|
const afterFetch = useRef(false);
|
||||||
const isFetchingFiltered = useRef(false);
|
|
||||||
const isFetching = useRef(false);
|
const isFetching = useRef(false);
|
||||||
|
|
||||||
const countNewVideos = useSelector(
|
|
||||||
(state: RootState) => state.video.countNewVideos
|
|
||||||
);
|
|
||||||
|
|
||||||
const videoSelector = useSelector((state: RootState) => state.video);
|
|
||||||
|
|
||||||
const { videos: globalVideos } = useSelector(
|
|
||||||
(state: RootState) => state.video
|
|
||||||
);
|
|
||||||
|
|
||||||
const { getVideos, getNewVideos, checkNewVideos, getVideosFiltered } =
|
const { getVideos, getNewVideos, checkNewVideos, getVideosFiltered } =
|
||||||
useFetchVideos();
|
useFetchVideos();
|
||||||
|
|
||||||
@ -357,16 +322,9 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
fontSize: "18px",
|
fontSize: "18px",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FiltersTitle>
|
|
||||||
Categories
|
|
||||||
<ExpandMoreSVG
|
|
||||||
color={theme.palette.text.primary}
|
|
||||||
height={"22"}
|
|
||||||
width={"22"}
|
|
||||||
/>
|
|
||||||
</FiltersTitle>
|
|
||||||
<FiltersSubContainer>
|
<FiltersSubContainer>
|
||||||
<FormControl sx={{ width: "100%" }}>
|
<FormControl sx={{ width: "100%", marginTop: "30px" }}>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@ -466,14 +424,6 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
</Box>
|
</Box>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FiltersSubContainer>
|
</FiltersSubContainer>
|
||||||
<FiltersTitle>
|
|
||||||
Type
|
|
||||||
<ExpandMoreSVG
|
|
||||||
color={theme.palette.text.primary}
|
|
||||||
height={"22"}
|
|
||||||
width={"22"}
|
|
||||||
/>
|
|
||||||
</FiltersTitle>
|
|
||||||
<FiltersSubContainer>
|
<FiltersSubContainer>
|
||||||
<FiltersRow>
|
<FiltersRow>
|
||||||
Videos
|
Videos
|
||||||
@ -551,7 +501,7 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
sx={{ fontSize: tabFontSize }}
|
sx={{ fontSize: tabFontSize }}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
label="Subsciptions"
|
label="Subscriptions"
|
||||||
value={subscriptionTabValue}
|
value={subscriptionTabValue}
|
||||||
sx={{ fontSize: tabFontSize }}
|
sx={{ fontSize: tabFontSize }}
|
||||||
/>
|
/>
|
||||||
@ -564,11 +514,19 @@ export const Home = ({ mode }: HomeProps) => {
|
|||||||
></LazyLoad>
|
></LazyLoad>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel value={subscriptionTabValue} sx={{ width: "100%" }}>
|
<TabPanel value={subscriptionTabValue} sx={{ width: "100%" }}>
|
||||||
<VideoList videos={videos} />
|
{persistSelector.subscriptionList.length > 0 ? (
|
||||||
<LazyLoad
|
<>
|
||||||
onLoadMore={getVideosHandler}
|
<VideoList videos={videos} />
|
||||||
isLoading={isLoading}
|
<LazyLoad
|
||||||
></LazyLoad>
|
onLoadMore={getVideosHandler}
|
||||||
|
isLoading={isLoading}
|
||||||
|
></LazyLoad>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<div style={{ textAlign: "center" }}>
|
||||||
|
You have no subscriptions
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
</TabContext>
|
</TabContext>
|
||||||
</Box>
|
</Box>
|
||||||
|
@ -196,7 +196,7 @@ export const NameContainer = styled(Box)(({ theme }) => ({
|
|||||||
justifyContent: "flex-start",
|
justifyContent: "flex-start",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: "10px",
|
gap: "10px",
|
||||||
marginBottom: "10px",
|
marginBottom: "2px",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
export const MyStoresCard = styled(Box)(({ theme }) => ({
|
export const MyStoresCard = styled(Box)(({ theme }) => ({
|
||||||
|
@ -64,7 +64,7 @@ export const VideoList = ({ videos }: VideoListProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VideoCardContainer>
|
<VideoCardContainer>
|
||||||
{videos.map((video: any, index: number) => {
|
{videos.map((video: any) => {
|
||||||
const fullId = video ? `${video.id}-${video.user}` : undefined;
|
const fullId = video ? `${video.id}-${video.user}` : undefined;
|
||||||
const existingVideo = hashMapVideos[fullId];
|
const existingVideo = hashMapVideos[fullId];
|
||||||
let hasHash = false;
|
let hasHash = false;
|
||||||
@ -269,9 +269,11 @@ export const VideoList = ({ videos }: VideoListProps) => {
|
|||||||
</VideoCardName>
|
</VideoCardName>
|
||||||
</NameContainer>
|
</NameContainer>
|
||||||
{videoObj?.created && (
|
{videoObj?.created && (
|
||||||
<VideoUploadDate>
|
<Box sx={{ flexDirection: "row", width: "100%" }}>
|
||||||
{formatDate(videoObj.created)}
|
<VideoUploadDate sx={{ display: "inline" }}>
|
||||||
</VideoUploadDate>
|
{formatDate(videoObj.created)}
|
||||||
|
</VideoUploadDate>
|
||||||
|
</Box>
|
||||||
)}
|
)}
|
||||||
</BottomParent>
|
</BottomParent>
|
||||||
</VideoCard>
|
</VideoCard>
|
||||||
|
59
src/state/features/persistSlice.ts
Normal file
59
src/state/features/persistSlice.ts
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||||
|
import { subscriptionTabValue } from "../../constants/Misc.ts";
|
||||||
|
|
||||||
|
type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down";
|
||||||
|
interface settingsState {
|
||||||
|
selectedTab: string;
|
||||||
|
stretchVideoSetting: StretchVideoType;
|
||||||
|
filterType: string;
|
||||||
|
subscriptionList: string[];
|
||||||
|
playbackRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialState: settingsState = {
|
||||||
|
selectedTab: subscriptionTabValue,
|
||||||
|
stretchVideoSetting: "contain",
|
||||||
|
filterType: "videos",
|
||||||
|
subscriptionList: [],
|
||||||
|
playbackRate: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const persistSlice = createSlice({
|
||||||
|
name: "persist",
|
||||||
|
initialState,
|
||||||
|
reducers: {
|
||||||
|
setHomePageSelectedTab: (state, action) => {
|
||||||
|
state.selectedTab = action.payload;
|
||||||
|
},
|
||||||
|
setStretchVideoSetting: (state, action) => {
|
||||||
|
state.stretchVideoSetting = action.payload;
|
||||||
|
},
|
||||||
|
subscribe: (state, action: PayloadAction<string>) => {
|
||||||
|
const currentSubscriptions = state.subscriptionList;
|
||||||
|
if (!currentSubscriptions.includes(action.payload)) {
|
||||||
|
state.subscriptionList = [...currentSubscriptions, action.payload];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unSubscribe: (state, action) => {
|
||||||
|
state.subscriptionList = state.subscriptionList.filter(
|
||||||
|
item => item !== action.payload
|
||||||
|
);
|
||||||
|
},
|
||||||
|
setReduxPlaybackRate: (state, action) => {
|
||||||
|
state.playbackRate = action.payload;
|
||||||
|
},
|
||||||
|
changeFilterType: (state, action) => {
|
||||||
|
state.filterType = action.payload;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const {
|
||||||
|
setHomePageSelectedTab,
|
||||||
|
subscribe,
|
||||||
|
unSubscribe,
|
||||||
|
setReduxPlaybackRate,
|
||||||
|
changeFilterType,
|
||||||
|
} = persistSlice.actions;
|
||||||
|
|
||||||
|
export default persistSlice.reducer;
|
@ -1,30 +0,0 @@
|
|||||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
|
||||||
import { subscriptionTabValue } from "../../constants/Misc.ts";
|
|
||||||
|
|
||||||
type StretchVideoType = "contain" | "fill" | "cover" | "none" | "scale-down";
|
|
||||||
interface settingsState {
|
|
||||||
selectedTab: string;
|
|
||||||
stretchVideoSetting: StretchVideoType;
|
|
||||||
}
|
|
||||||
|
|
||||||
const initialState: settingsState = {
|
|
||||||
selectedTab: subscriptionTabValue,
|
|
||||||
stretchVideoSetting: "contain",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const settingsSlice = createSlice({
|
|
||||||
name: "settings",
|
|
||||||
initialState,
|
|
||||||
reducers: {
|
|
||||||
setHomePageSelectedTab: (state, action) => {
|
|
||||||
state.selectedTab = action.payload;
|
|
||||||
},
|
|
||||||
setStretchVideoSetting: (state, action) => {
|
|
||||||
state.stretchVideoSetting = action.payload;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export const { setHomePageSelectedTab } = settingsSlice.actions;
|
|
||||||
|
|
||||||
export default settingsSlice.reducer;
|
|
@ -8,14 +8,12 @@ interface GlobalState {
|
|||||||
countNewVideos: number;
|
countNewVideos: number;
|
||||||
isFiltering: boolean;
|
isFiltering: boolean;
|
||||||
filterValue: string;
|
filterValue: string;
|
||||||
filterType: string;
|
|
||||||
filterSearch: string;
|
filterSearch: string;
|
||||||
filterName: string;
|
filterName: string;
|
||||||
selectedCategoryVideos: any;
|
selectedCategoryVideos: any;
|
||||||
selectedSubCategoryVideos: any;
|
selectedSubCategoryVideos: any;
|
||||||
editVideoProperties: any;
|
editVideoProperties: any;
|
||||||
editPlaylistProperties: any;
|
editPlaylistProperties: any;
|
||||||
subscriptionList: string[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: GlobalState = {
|
const initialState: GlobalState = {
|
||||||
@ -26,14 +24,12 @@ const initialState: GlobalState = {
|
|||||||
countNewVideos: 0,
|
countNewVideos: 0,
|
||||||
isFiltering: false,
|
isFiltering: false,
|
||||||
filterValue: "",
|
filterValue: "",
|
||||||
filterType: "videos",
|
|
||||||
filterSearch: "",
|
filterSearch: "",
|
||||||
filterName: "",
|
filterName: "",
|
||||||
selectedCategoryVideos: null,
|
selectedCategoryVideos: null,
|
||||||
selectedSubCategoryVideos: null,
|
selectedSubCategoryVideos: null,
|
||||||
editVideoProperties: null,
|
editVideoProperties: null,
|
||||||
editPlaylistProperties: null,
|
editPlaylistProperties: null,
|
||||||
subscriptionList: [],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface Video {
|
export interface Video {
|
||||||
@ -62,9 +58,7 @@ export const videoSlice = createSlice({
|
|||||||
setEditPlaylist: (state, action) => {
|
setEditPlaylist: (state, action) => {
|
||||||
state.editPlaylistProperties = action.payload;
|
state.editPlaylistProperties = action.payload;
|
||||||
},
|
},
|
||||||
changeFilterType: (state, action) => {
|
|
||||||
state.filterType = action.payload;
|
|
||||||
},
|
|
||||||
changefilterSearch: (state, action) => {
|
changefilterSearch: (state, action) => {
|
||||||
state.filterSearch = action.payload;
|
state.filterSearch = action.payload;
|
||||||
},
|
},
|
||||||
@ -174,17 +168,6 @@ export const videoSlice = createSlice({
|
|||||||
|
|
||||||
state.videos = state.videos.filter(item => item.user !== username);
|
state.videos = state.videos.filter(item => item.user !== username);
|
||||||
},
|
},
|
||||||
subscribe: (state, action: PayloadAction<string>) => {
|
|
||||||
const currentSubscriptions = state.subscriptionList;
|
|
||||||
if (!currentSubscriptions.includes(action.payload)) {
|
|
||||||
state.subscriptionList = [...currentSubscriptions, action.payload];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
unSubscribe: (state, action) => {
|
|
||||||
state.subscriptionList = state.subscriptionList.filter(
|
|
||||||
item => item !== action.payload
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -205,7 +188,6 @@ export const {
|
|||||||
setIsFiltering,
|
setIsFiltering,
|
||||||
setFilterValue,
|
setFilterValue,
|
||||||
clearVideoList,
|
clearVideoList,
|
||||||
changeFilterType,
|
|
||||||
changefilterSearch,
|
changefilterSearch,
|
||||||
changefilterName,
|
changefilterName,
|
||||||
changeSelectedCategoryVideos,
|
changeSelectedCategoryVideos,
|
||||||
@ -214,8 +196,6 @@ export const {
|
|||||||
setEditVideo,
|
setEditVideo,
|
||||||
setEditPlaylist,
|
setEditPlaylist,
|
||||||
addtoHashMapSuperlikes,
|
addtoHashMapSuperlikes,
|
||||||
subscribe,
|
|
||||||
unSubscribe,
|
|
||||||
} = videoSlice.actions;
|
} = videoSlice.actions;
|
||||||
|
|
||||||
export default videoSlice.reducer;
|
export default videoSlice.reducer;
|
||||||
|
@ -3,7 +3,7 @@ import notificationsReducer from "./features/notificationsSlice";
|
|||||||
import authReducer from "./features/authSlice";
|
import authReducer from "./features/authSlice";
|
||||||
import globalReducer from "./features/globalSlice";
|
import globalReducer from "./features/globalSlice";
|
||||||
import videoReducer from "./features/videoSlice";
|
import videoReducer from "./features/videoSlice";
|
||||||
import settingsReducer from "./features/settingsSlice";
|
import settingsReducer from "./features/persistSlice.ts";
|
||||||
import {
|
import {
|
||||||
persistReducer,
|
persistReducer,
|
||||||
FLUSH,
|
FLUSH,
|
||||||
@ -15,15 +15,8 @@ import {
|
|||||||
} from "redux-persist";
|
} from "redux-persist";
|
||||||
import storage from "redux-persist/lib/storage";
|
import storage from "redux-persist/lib/storage";
|
||||||
|
|
||||||
const persistVideoConfig = {
|
|
||||||
key: "video",
|
|
||||||
version: 1,
|
|
||||||
storage,
|
|
||||||
whitelist: ["subscriptionList", "filterType"],
|
|
||||||
};
|
|
||||||
|
|
||||||
const persistSettingsConfig = {
|
const persistSettingsConfig = {
|
||||||
key: "settings",
|
key: "persist",
|
||||||
version: 1,
|
version: 1,
|
||||||
storage,
|
storage,
|
||||||
};
|
};
|
||||||
@ -32,8 +25,8 @@ const reducer = combineReducers({
|
|||||||
notifications: notificationsReducer,
|
notifications: notificationsReducer,
|
||||||
auth: authReducer,
|
auth: authReducer,
|
||||||
global: globalReducer,
|
global: globalReducer,
|
||||||
video: persistReducer(persistVideoConfig, videoReducer),
|
video: videoReducer,
|
||||||
settings: persistReducer(persistSettingsConfig, settingsReducer),
|
persist: persistReducer(persistSettingsConfig, settingsReducer),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user