Add gallery reducer for timeline view as well
This commit is contained in:
parent
a069eff0b2
commit
c992fe8933
|
@ -34,6 +34,7 @@ module.exports = {
|
||||||
'react/display-name': 'off',
|
'react/display-name': 'off',
|
||||||
'@typescript-eslint/no-var-requires': 'off',
|
'@typescript-eslint/no-var-requires': 'off',
|
||||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
import React, { useReducer } from 'react'
|
import React, { useContext, useEffect, useReducer } from 'react'
|
||||||
import AlbumTitle from '../AlbumTitle'
|
import AlbumTitle from '../AlbumTitle'
|
||||||
import PhotoGallery from '../photoGallery/PhotoGallery'
|
import PhotoGallery from '../photoGallery/PhotoGallery'
|
||||||
import AlbumBoxes from './AlbumBoxes'
|
import AlbumBoxes from './AlbumBoxes'
|
||||||
import AlbumFilter from '../AlbumFilter'
|
import AlbumFilter from '../AlbumFilter'
|
||||||
import { albumQuery_album } from '../../Pages/AlbumPage/__generated__/albumQuery'
|
import { albumQuery_album } from '../../Pages/AlbumPage/__generated__/albumQuery'
|
||||||
import { OrderDirection } from '../../../__generated__/globalTypes'
|
import { OrderDirection } from '../../../__generated__/globalTypes'
|
||||||
import { photoGalleryReducer } from '../photoGallery/photoGalleryReducer'
|
import {
|
||||||
|
photoGalleryReducer,
|
||||||
|
urlPresentModeSetupHook,
|
||||||
|
} from '../photoGallery/photoGalleryReducer'
|
||||||
|
import { SidebarContext } from '../sidebar/Sidebar'
|
||||||
|
import MediaSidebar from '../sidebar/MediaSidebar'
|
||||||
|
|
||||||
type AlbumGalleryProps = {
|
type AlbumGalleryProps = {
|
||||||
album?: albumQuery_album
|
album?: albumQuery_album
|
||||||
|
@ -33,10 +38,7 @@ const AlbumGallery = React.forwardRef(
|
||||||
}: AlbumGalleryProps,
|
}: AlbumGalleryProps,
|
||||||
ref: React.ForwardedRef<HTMLDivElement>
|
ref: React.ForwardedRef<HTMLDivElement>
|
||||||
) => {
|
) => {
|
||||||
// const [imageState, setImageState] = useState<ImageStateType>({
|
const { updateSidebar } = useContext(SidebarContext)
|
||||||
// activeImage: -1,
|
|
||||||
// presenting: false,
|
|
||||||
// })
|
|
||||||
|
|
||||||
const [mediaState, dispatchMedia] = useReducer(photoGalleryReducer, {
|
const [mediaState, dispatchMedia] = useReducer(photoGalleryReducer, {
|
||||||
presenting: false,
|
presenting: false,
|
||||||
|
@ -44,38 +46,31 @@ const AlbumGallery = React.forwardRef(
|
||||||
media: album?.media || [],
|
media: album?.media || [],
|
||||||
})
|
})
|
||||||
|
|
||||||
// const setPresentingWithHistory = (presenting: boolean) => {
|
useEffect(() => {
|
||||||
// setPresenting(presenting)
|
dispatchMedia({ type: 'replaceMedia', media: album?.media || [] })
|
||||||
// if (presenting) {
|
}, [album?.media])
|
||||||
// history.pushState({ imageState }, '')
|
|
||||||
// } else {
|
|
||||||
// history.back()
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// const updateHistory = (imageState: ImageStateType) => {
|
useEffect(() => {
|
||||||
// history.replaceState({ imageState }, '')
|
if (mediaState.activeIndex != -1) {
|
||||||
// return imageState
|
updateSidebar(
|
||||||
// }
|
<MediaSidebar media={mediaState.media[mediaState.activeIndex]} />
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
updateSidebar(null)
|
||||||
|
}
|
||||||
|
}, [mediaState.activeIndex])
|
||||||
|
|
||||||
// useEffect(() => {
|
urlPresentModeSetupHook({
|
||||||
// const updateImageState = (event: PopStateEvent) => {
|
dispatchMedia,
|
||||||
// setImageState(event.state.imageState)
|
openPresentMode: event => {
|
||||||
// }
|
dispatchMedia({
|
||||||
|
type: 'openPresentMode',
|
||||||
// window.addEventListener('popstate', updateImageState)
|
activeIndex: event.state.activeIndex,
|
||||||
|
})
|
||||||
// return () => {
|
},
|
||||||
// window.removeEventListener('popstate', updateImageState)
|
})
|
||||||
// }
|
|
||||||
// }, [imageState])
|
|
||||||
|
|
||||||
// useEffect(() => {
|
|
||||||
// setActiveImage(-1)
|
|
||||||
// }, [album])
|
|
||||||
|
|
||||||
let subAlbumElement = null
|
let subAlbumElement = null
|
||||||
|
|
||||||
if (album) {
|
if (album) {
|
||||||
if (album.subAlbums.length > 0) {
|
if (album.subAlbums.length > 0) {
|
||||||
subAlbumElement = (
|
subAlbumElement = (
|
||||||
|
|
|
@ -1,31 +1,20 @@
|
||||||
import React, { useContext } from 'react'
|
import React from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { Loader } from 'semantic-ui-react'
|
import { Loader } from 'semantic-ui-react'
|
||||||
import { MediaThumbnail, PhotoThumbnail } from './MediaThumbnail'
|
import { MediaThumbnail, PhotoThumbnail } from './MediaThumbnail'
|
||||||
import PresentView from './presentView/PresentView'
|
import PresentView from './presentView/PresentView'
|
||||||
import { SidebarContext } from '../sidebar/Sidebar'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { PresentMediaProps_Media } from './presentView/PresentMedia'
|
import { PresentMediaProps_Media } from './presentView/PresentMedia'
|
||||||
import { sidebarPhoto_media_thumbnail } from '../sidebar/__generated__/sidebarPhoto'
|
import { sidebarPhoto_media_thumbnail } from '../sidebar/__generated__/sidebarPhoto'
|
||||||
import {
|
import {
|
||||||
|
openPresentModeAction,
|
||||||
PhotoGalleryAction,
|
PhotoGalleryAction,
|
||||||
PhotoGalleryState,
|
PhotoGalleryState,
|
||||||
selectImageAction,
|
|
||||||
} from './photoGalleryReducer'
|
} from './photoGalleryReducer'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
|
||||||
import {
|
import {
|
||||||
markMediaFavorite,
|
toggleFavoriteAction,
|
||||||
markMediaFavoriteVariables,
|
useMarkFavoriteMutation,
|
||||||
} from './__generated__/markMediaFavorite'
|
} from './photoGalleryMutations'
|
||||||
|
|
||||||
const markFavoriteMutation = gql`
|
|
||||||
mutation markMediaFavorite($mediaId: ID!, $favorite: Boolean!) {
|
|
||||||
favoriteMedia(mediaId: $mediaId, favorite: $favorite) {
|
|
||||||
id
|
|
||||||
favorite
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const Gallery = styled.div`
|
const Gallery = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -68,12 +57,7 @@ const PhotoGallery = ({
|
||||||
}: PhotoGalleryProps) => {
|
}: PhotoGalleryProps) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
const { updateSidebar } = useContext(SidebarContext)
|
const [markFavorite] = useMarkFavoriteMutation()
|
||||||
|
|
||||||
const [markFavorite] = useMutation<
|
|
||||||
markMediaFavorite,
|
|
||||||
markMediaFavoriteVariables
|
|
||||||
>(markFavoriteMutation)
|
|
||||||
|
|
||||||
const { media, activeIndex, presenting } = mediaState
|
const { media, activeIndex, presenting } = mediaState
|
||||||
|
|
||||||
|
@ -88,33 +72,19 @@ const PhotoGallery = ({
|
||||||
media={media}
|
media={media}
|
||||||
active={active}
|
active={active}
|
||||||
selectImage={() => {
|
selectImage={() => {
|
||||||
selectImageAction({
|
dispatchMedia({
|
||||||
|
type: 'selectImage',
|
||||||
index,
|
index,
|
||||||
mediaState,
|
|
||||||
dispatchMedia,
|
|
||||||
updateSidebar,
|
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
clickFavorite={() => {
|
clickFavorite={() => {
|
||||||
markFavorite({
|
toggleFavoriteAction({
|
||||||
variables: {
|
media,
|
||||||
mediaId: media.id,
|
markFavorite,
|
||||||
favorite: !media.favorite,
|
|
||||||
},
|
|
||||||
optimisticResponse: {
|
|
||||||
favoriteMedia: {
|
|
||||||
id: media.id,
|
|
||||||
favorite: !media.favorite,
|
|
||||||
__typename: 'Media',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
clickPresent={() => {
|
clickPresent={() => {
|
||||||
dispatchMedia({
|
openPresentModeAction({ dispatchMedia, activeIndex: index })
|
||||||
type: 'setPresenting',
|
|
||||||
presenting: true,
|
|
||||||
})
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
@ -135,7 +105,10 @@ const PhotoGallery = ({
|
||||||
<PhotoFiller />
|
<PhotoFiller />
|
||||||
</Gallery>
|
</Gallery>
|
||||||
{presenting && (
|
{presenting && (
|
||||||
<PresentView mediaState={mediaState} dispatchMedia={dispatchMedia} />
|
<PresentView
|
||||||
|
activeMedia={mediaState.media[mediaState.activeIndex]}
|
||||||
|
dispatchMedia={dispatchMedia}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</ClearWrap>
|
</ClearWrap>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { gql, MutationFunction, useMutation } from '@apollo/client'
|
||||||
|
import { PhotoGalleryProps_Media } from './PhotoGallery'
|
||||||
|
import {
|
||||||
|
markMediaFavorite,
|
||||||
|
markMediaFavoriteVariables,
|
||||||
|
} from './__generated__/markMediaFavorite'
|
||||||
|
|
||||||
|
const markFavoriteMutation = gql`
|
||||||
|
mutation markMediaFavorite($mediaId: ID!, $favorite: Boolean!) {
|
||||||
|
favoriteMedia(mediaId: $mediaId, favorite: $favorite) {
|
||||||
|
id
|
||||||
|
favorite
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export const useMarkFavoriteMutation = () => {
|
||||||
|
return useMutation<markMediaFavorite, markMediaFavoriteVariables>(
|
||||||
|
markFavoriteMutation
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const toggleFavoriteAction = ({
|
||||||
|
media,
|
||||||
|
markFavorite,
|
||||||
|
}: {
|
||||||
|
media: PhotoGalleryProps_Media
|
||||||
|
markFavorite: MutationFunction<markMediaFavorite, markMediaFavoriteVariables>
|
||||||
|
}) => {
|
||||||
|
markFavorite({
|
||||||
|
variables: {
|
||||||
|
mediaId: media.id,
|
||||||
|
favorite: !media.favorite,
|
||||||
|
},
|
||||||
|
optimisticResponse: {
|
||||||
|
favoriteMedia: {
|
||||||
|
id: media.id,
|
||||||
|
favorite: !media.favorite,
|
||||||
|
__typename: 'Media',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
|
@ -1,24 +1,28 @@
|
||||||
import React from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import { UpdateSidebarFn } from '../sidebar/Sidebar'
|
|
||||||
import { PhotoGalleryProps_Media } from './PhotoGallery'
|
import { PhotoGalleryProps_Media } from './PhotoGallery'
|
||||||
import MediaSidebar from '../sidebar/MediaSidebar'
|
|
||||||
|
|
||||||
export type PhotoGalleryState = {
|
export interface PhotoGalleryState {
|
||||||
presenting: boolean
|
presenting: boolean
|
||||||
activeIndex: number
|
activeIndex: number
|
||||||
media: PhotoGalleryProps_Media[]
|
media: PhotoGalleryProps_Media[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PhotoGalleryAction =
|
export type GalleryAction =
|
||||||
| { type: 'nextImage' }
|
| { type: 'nextImage' }
|
||||||
| { type: 'previousImage' }
|
| { type: 'previousImage' }
|
||||||
| { type: 'setPresenting'; presenting: boolean }
|
| { type: 'closePresentMode' }
|
||||||
|
|
||||||
|
export type PhotoGalleryAction =
|
||||||
|
| GalleryAction
|
||||||
|
| { type: 'openPresentMode'; activeIndex: number }
|
||||||
| { type: 'selectImage'; index: number }
|
| { type: 'selectImage'; index: number }
|
||||||
|
| { type: 'replaceMedia'; media: PhotoGalleryProps_Media[] }
|
||||||
|
|
||||||
export function photoGalleryReducer(
|
export function photoGalleryReducer(
|
||||||
state: PhotoGalleryState,
|
state: PhotoGalleryState,
|
||||||
action: PhotoGalleryAction
|
action: PhotoGalleryAction
|
||||||
): PhotoGalleryState {
|
): PhotoGalleryState {
|
||||||
|
console.log('photo gallery reducer:', state, action)
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'nextImage':
|
case 'nextImage':
|
||||||
return {
|
return {
|
||||||
|
@ -37,10 +41,16 @@ export function photoGalleryReducer(
|
||||||
activeIndex: state.activeIndex - 1,
|
activeIndex: state.activeIndex - 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'setPresenting':
|
case 'openPresentMode':
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
presenting: action.presenting,
|
presenting: true,
|
||||||
|
activeIndex: action.activeIndex,
|
||||||
|
}
|
||||||
|
case 'closePresentMode':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
presenting: false,
|
||||||
}
|
}
|
||||||
case 'selectImage':
|
case 'selectImage':
|
||||||
return {
|
return {
|
||||||
|
@ -50,25 +60,64 @@ export function photoGalleryReducer(
|
||||||
Math.min(state.media.length - 1, action.index)
|
Math.min(state.media.length - 1, action.index)
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
case 'replaceMedia':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
media: action.media,
|
||||||
|
activeIndex: -1,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const selectImageAction = ({
|
export const urlPresentModeSetupHook = ({
|
||||||
index,
|
|
||||||
mediaState,
|
|
||||||
dispatchMedia,
|
dispatchMedia,
|
||||||
updateSidebar,
|
openPresentMode,
|
||||||
}: {
|
}: {
|
||||||
index: number
|
dispatchMedia: React.Dispatch<GalleryAction>
|
||||||
mediaState: PhotoGalleryState
|
openPresentMode: (event: PopStateEvent) => void
|
||||||
dispatchMedia: React.Dispatch<PhotoGalleryAction>
|
|
||||||
updateSidebar: UpdateSidebarFn
|
|
||||||
}) => {
|
}) => {
|
||||||
updateSidebar(
|
useEffect(() => {
|
||||||
<MediaSidebar media={mediaState.media[mediaState.activeIndex]} />
|
const urlChangeListener = (event: PopStateEvent) => {
|
||||||
)
|
if (event.state.presenting === true) {
|
||||||
dispatchMedia({
|
openPresentMode(event)
|
||||||
type: 'selectImage',
|
} else {
|
||||||
index,
|
dispatchMedia({ type: 'closePresentMode' })
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('popstate', urlChangeListener)
|
||||||
|
|
||||||
|
history.replaceState({ presenting: false }, '')
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('popstate', urlChangeListener)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
export const openPresentModeAction = ({
|
||||||
|
dispatchMedia,
|
||||||
|
activeIndex,
|
||||||
|
}: {
|
||||||
|
dispatchMedia: React.Dispatch<PhotoGalleryAction>
|
||||||
|
activeIndex: number
|
||||||
|
}) => {
|
||||||
|
dispatchMedia({
|
||||||
|
type: 'openPresentMode',
|
||||||
|
activeIndex: activeIndex,
|
||||||
|
})
|
||||||
|
|
||||||
|
history.pushState({ presenting: true, activeIndex }, '')
|
||||||
|
}
|
||||||
|
|
||||||
|
export const closePresentModeAction = ({
|
||||||
|
dispatchMedia,
|
||||||
|
}: {
|
||||||
|
dispatchMedia: React.Dispatch<GalleryAction>
|
||||||
|
}) => {
|
||||||
|
dispatchMedia({
|
||||||
|
type: 'closePresentMode',
|
||||||
|
})
|
||||||
|
|
||||||
|
history.back()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState, useRef, useEffect } from 'react'
|
import React, { useState, useRef, useEffect } from 'react'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { debounce, DebouncedFn } from '../../../helpers/utils'
|
import { debounce, DebouncedFn } from '../../../helpers/utils'
|
||||||
import { PhotoGalleryAction } from '../photoGalleryReducer'
|
import { closePresentModeAction, GalleryAction } from '../photoGalleryReducer'
|
||||||
|
|
||||||
import ExitIcon from './icons/Exit'
|
import ExitIcon from './icons/Exit'
|
||||||
import NextIcon from './icons/Next'
|
import NextIcon from './icons/Next'
|
||||||
|
@ -66,7 +66,7 @@ const NavigationButton = styled(OverlayButton)<{ float: 'left' | 'right' }>`
|
||||||
|
|
||||||
type PresentNavigationOverlayProps = {
|
type PresentNavigationOverlayProps = {
|
||||||
children?: React.ReactChild
|
children?: React.ReactChild
|
||||||
dispatchMedia: React.Dispatch<PhotoGalleryAction>
|
dispatchMedia: React.Dispatch<GalleryAction>
|
||||||
}
|
}
|
||||||
|
|
||||||
const PresentNavigationOverlay = ({
|
const PresentNavigationOverlay = ({
|
||||||
|
@ -113,9 +113,7 @@ const PresentNavigationOverlay = ({
|
||||||
</NavigationButton>
|
</NavigationButton>
|
||||||
<ExitButton
|
<ExitButton
|
||||||
className={hide ? 'hide' : undefined}
|
className={hide ? 'hide' : undefined}
|
||||||
onClick={() =>
|
onClick={() => closePresentModeAction({ dispatchMedia })}
|
||||||
dispatchMedia({ type: 'setPresenting', presenting: false })
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<ExitIcon />
|
<ExitIcon />
|
||||||
</ExitButton>
|
</ExitButton>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
import styled, { createGlobalStyle } from 'styled-components'
|
import styled, { createGlobalStyle } from 'styled-components'
|
||||||
import PresentNavigationOverlay from './PresentNavigationOverlay'
|
import PresentNavigationOverlay from './PresentNavigationOverlay'
|
||||||
import PresentMedia from './PresentMedia'
|
import PresentMedia, { PresentMediaProps_Media } from './PresentMedia'
|
||||||
import { PhotoGalleryAction, PhotoGalleryState } from '../photoGalleryReducer'
|
import { closePresentModeAction, GalleryAction } from '../photoGalleryReducer'
|
||||||
|
|
||||||
const StyledContainer = styled.div`
|
const StyledContainer = styled.div`
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -24,14 +24,14 @@ const PreventScroll = createGlobalStyle`
|
||||||
type PresentViewProps = {
|
type PresentViewProps = {
|
||||||
className?: string
|
className?: string
|
||||||
imageLoaded?(): void
|
imageLoaded?(): void
|
||||||
mediaState: PhotoGalleryState
|
activeMedia: PresentMediaProps_Media
|
||||||
dispatchMedia: React.Dispatch<PhotoGalleryAction>
|
dispatchMedia: React.Dispatch<GalleryAction>
|
||||||
}
|
}
|
||||||
|
|
||||||
const PresentView = ({
|
const PresentView = ({
|
||||||
className,
|
className,
|
||||||
imageLoaded,
|
imageLoaded,
|
||||||
mediaState,
|
activeMedia,
|
||||||
dispatchMedia,
|
dispatchMedia,
|
||||||
}: PresentViewProps) => {
|
}: PresentViewProps) => {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -48,7 +48,8 @@ const PresentView = ({
|
||||||
|
|
||||||
if (e.key == 'Escape') {
|
if (e.key == 'Escape') {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
dispatchMedia({ type: 'setPresenting', presenting: false })
|
// dispatchMedia({ type: 'setPresenting', presenting: false })
|
||||||
|
closePresentModeAction({ dispatchMedia })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,10 +64,7 @@ const PresentView = ({
|
||||||
<StyledContainer {...className}>
|
<StyledContainer {...className}>
|
||||||
<PreventScroll />
|
<PreventScroll />
|
||||||
<PresentNavigationOverlay dispatchMedia={dispatchMedia}>
|
<PresentNavigationOverlay dispatchMedia={dispatchMedia}>
|
||||||
<PresentMedia
|
<PresentMedia media={activeMedia} imageLoaded={imageLoaded} />
|
||||||
media={mediaState.media[mediaState.activeIndex]}
|
|
||||||
imageLoaded={imageLoaded}
|
|
||||||
/>
|
|
||||||
</PresentNavigationOverlay>
|
</PresentNavigationOverlay>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useState, useCallback, useRef, useEffect } from 'react'
|
import React, { useRef, useEffect, useReducer, useContext } from 'react'
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import { useQuery, gql } from '@apollo/client'
|
import { useQuery, gql } from '@apollo/client'
|
||||||
import TimelineGroupDate from './TimelineGroupDate'
|
import TimelineGroupDate from './TimelineGroupDate'
|
||||||
|
@ -16,6 +16,13 @@ import {
|
||||||
myTimelineVariables,
|
myTimelineVariables,
|
||||||
myTimeline_myTimeline,
|
myTimeline_myTimeline,
|
||||||
} from './__generated__/myTimeline'
|
} from './__generated__/myTimeline'
|
||||||
|
import {
|
||||||
|
getActiveTimelineImage as getActiveTimelineMedia,
|
||||||
|
timelineGalleryReducer,
|
||||||
|
} from './timelineGalleryReducer'
|
||||||
|
import MediaSidebar from '../sidebar/MediaSidebar'
|
||||||
|
import { SidebarContext } from '../sidebar/Sidebar'
|
||||||
|
import { urlPresentModeSetupHook } from '../photoGallery/photoGalleryReducer'
|
||||||
|
|
||||||
const MY_TIMELINE_QUERY = gql`
|
const MY_TIMELINE_QUERY = gql`
|
||||||
query myTimeline($onlyFavorites: Boolean, $limit: Int, $offset: Int) {
|
query myTimeline($onlyFavorites: Boolean, $limit: Int, $offset: Int) {
|
||||||
|
@ -64,14 +71,14 @@ export type TimelineActiveIndex = {
|
||||||
media: number
|
media: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TimelineGroup = {
|
||||||
|
date: string
|
||||||
|
groups: myTimeline_myTimeline[]
|
||||||
|
}
|
||||||
|
|
||||||
const TimelineGallery = () => {
|
const TimelineGallery = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [activeIndex, setActiveIndex] = useState({
|
const { updateSidebar } = useContext(SidebarContext)
|
||||||
dateGroup: -1,
|
|
||||||
albumGroup: -1,
|
|
||||||
media: -1,
|
|
||||||
})
|
|
||||||
const [presenting, setPresenting] = useState(false)
|
|
||||||
|
|
||||||
const { getParam, setParam } = useURLParameters()
|
const { getParam, setParam } = useURLParameters()
|
||||||
|
|
||||||
|
@ -81,68 +88,15 @@ const TimelineGallery = () => {
|
||||||
|
|
||||||
const favoritesNeedsRefresh = useRef(false)
|
const favoritesNeedsRefresh = useRef(false)
|
||||||
|
|
||||||
const nextMedia = useCallback(() => {
|
const [mediaState, dispatchMedia] = useReducer(timelineGalleryReducer, {
|
||||||
setActiveIndex(activeIndex => {
|
presenting: false,
|
||||||
const albumGroups = dateGroupedAlbums[activeIndex.dateGroup].groups
|
timelineGroups: [],
|
||||||
const albumMedia = albumGroups[activeIndex.albumGroup].media
|
activeIndex: {
|
||||||
|
media: -1,
|
||||||
if (activeIndex.media < albumMedia.length - 1) {
|
album: -1,
|
||||||
return {
|
date: -1,
|
||||||
...activeIndex,
|
},
|
||||||
media: activeIndex.media + 1,
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeIndex.albumGroup < albumGroups.length - 1) {
|
|
||||||
return {
|
|
||||||
...activeIndex,
|
|
||||||
albumGroup: activeIndex.albumGroup + 1,
|
|
||||||
media: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeIndex.dateGroup < dateGroupedAlbums.length - 1) {
|
|
||||||
return {
|
|
||||||
dateGroup: activeIndex.dateGroup + 1,
|
|
||||||
albumGroup: 0,
|
|
||||||
media: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reached the end
|
|
||||||
return activeIndex
|
|
||||||
})
|
|
||||||
}, [activeIndex])
|
|
||||||
|
|
||||||
const previousMedia = useCallback(() => {
|
|
||||||
setActiveIndex(activeIndex => {
|
|
||||||
if (activeIndex.media > 0) {
|
|
||||||
return {
|
|
||||||
...activeIndex,
|
|
||||||
media: activeIndex.media - 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeIndex.albumGroup > 0) {
|
|
||||||
return {
|
|
||||||
...activeIndex,
|
|
||||||
albumGroup: activeIndex.albumGroup - 1,
|
|
||||||
media: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeIndex.dateGroup > 0) {
|
|
||||||
return {
|
|
||||||
dateGroup: activeIndex.dateGroup - 1,
|
|
||||||
albumGroup: 0,
|
|
||||||
media: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reached the start
|
|
||||||
return activeIndex
|
|
||||||
})
|
|
||||||
}, [activeIndex])
|
|
||||||
|
|
||||||
const { data, error, loading, refetch, fetchMore } = useQuery<
|
const { data, error, loading, refetch, fetchMore } = useQuery<
|
||||||
myTimeline,
|
myTimeline,
|
||||||
|
@ -166,12 +120,36 @@ const TimelineGallery = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (favoritesNeedsRefresh) {
|
dispatchMedia({
|
||||||
favoritesNeedsRefresh.current = false
|
type: 'replaceTimelineGroups',
|
||||||
refetch({
|
timeline: data?.myTimeline || [],
|
||||||
onlyFavorites: onlyFavorites,
|
})
|
||||||
})
|
}, [data])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const activeMedia = getActiveTimelineMedia({ mediaState })
|
||||||
|
if (activeMedia) {
|
||||||
|
updateSidebar(<MediaSidebar media={activeMedia} />)
|
||||||
|
} else {
|
||||||
|
updateSidebar(null)
|
||||||
}
|
}
|
||||||
|
}, [mediaState.activeIndex])
|
||||||
|
|
||||||
|
urlPresentModeSetupHook({
|
||||||
|
dispatchMedia,
|
||||||
|
openPresentMode: event => {
|
||||||
|
dispatchMedia({
|
||||||
|
type: 'openPresentMode',
|
||||||
|
activeIndex: event.state.activeIndex,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
favoritesNeedsRefresh.current = false
|
||||||
|
refetch({
|
||||||
|
onlyFavorites: onlyFavorites,
|
||||||
|
})
|
||||||
}, [onlyFavorites])
|
}, [onlyFavorites])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -186,51 +164,14 @@ const TimelineGallery = () => {
|
||||||
return <div>{error.message}</div>
|
return <div>{error.message}</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
type TimelineGroup = {
|
const timelineGroups = mediaState.timelineGroups.map((_, i) => (
|
||||||
date: string
|
<TimelineGroupDate
|
||||||
groups: myTimeline_myTimeline[]
|
key={i}
|
||||||
}
|
groupIndex={i}
|
||||||
|
mediaState={mediaState}
|
||||||
let timelineGroups = null
|
dispatchMedia={dispatchMedia}
|
||||||
let dateGroupedAlbums: TimelineGroup[] = []
|
/>
|
||||||
if (data?.myTimeline) {
|
))
|
||||||
dateGroupedAlbums = data.myTimeline.reduce((acc, val) => {
|
|
||||||
if (acc.length == 0 || acc[acc.length - 1].date != val.date) {
|
|
||||||
acc.push({
|
|
||||||
date: val.date,
|
|
||||||
groups: [val],
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
acc[acc.length - 1].groups.push(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc
|
|
||||||
}, [] as TimelineGroup[])
|
|
||||||
|
|
||||||
timelineGroups = dateGroupedAlbums.map(({ date, groups }, i) => (
|
|
||||||
<TimelineGroupDate
|
|
||||||
key={date}
|
|
||||||
date={date}
|
|
||||||
groups={groups}
|
|
||||||
activeIndex={
|
|
||||||
activeIndex.dateGroup == i
|
|
||||||
? activeIndex
|
|
||||||
: { albumGroup: -1, media: -1 }
|
|
||||||
}
|
|
||||||
setPresenting={setPresenting}
|
|
||||||
onSelectDateGroup={({ media, albumGroup }) => {
|
|
||||||
setActiveIndex({
|
|
||||||
media,
|
|
||||||
albumGroup,
|
|
||||||
dateGroup: i,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
onFavorite={() => {
|
|
||||||
favoritesNeedsRefresh.current = true
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -246,17 +187,10 @@ const TimelineGallery = () => {
|
||||||
active={!finishedLoadingMore && !loading}
|
active={!finishedLoadingMore && !loading}
|
||||||
text={t('general.loading.paginate.media', 'Loading more media')}
|
text={t('general.loading.paginate.media', 'Loading more media')}
|
||||||
/>
|
/>
|
||||||
{presenting && (
|
{mediaState.presenting && (
|
||||||
<PresentView
|
<PresentView
|
||||||
media={
|
activeMedia={getActiveTimelineMedia({ mediaState })!}
|
||||||
dateGroupedAlbums &&
|
dispatchMedia={dispatchMedia}
|
||||||
dateGroupedAlbums[activeIndex.dateGroup].groups[
|
|
||||||
activeIndex.albumGroup
|
|
||||||
].media[activeIndex.media]
|
|
||||||
}
|
|
||||||
nextImage={nextMedia}
|
|
||||||
previousImage={previousMedia}
|
|
||||||
setPresenting={setPresenting}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -2,12 +2,17 @@ import React, { useContext } from 'react'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
import { MediaThumbnail } from '../photoGallery/MediaThumbnail'
|
import { MediaThumbnail } from '../photoGallery/MediaThumbnail'
|
||||||
import MediaSidebar from '../sidebar/MediaSidebar'
|
import {
|
||||||
|
toggleFavoriteAction,
|
||||||
|
useMarkFavoriteMutation,
|
||||||
|
} from '../photoGallery/photoGalleryMutations'
|
||||||
import { SidebarContext } from '../sidebar/Sidebar'
|
import { SidebarContext } from '../sidebar/Sidebar'
|
||||||
import {
|
import {
|
||||||
myTimeline_myTimeline_album,
|
getActiveTimelineImage,
|
||||||
myTimeline_myTimeline_media,
|
openTimelinePresentMode,
|
||||||
} from './__generated__/myTimeline'
|
TimelineGalleryAction,
|
||||||
|
TimelineGalleryState,
|
||||||
|
} from './timelineGalleryReducer'
|
||||||
|
|
||||||
const MediaWrapper = styled.div`
|
const MediaWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -55,38 +60,55 @@ const TotalItemsBubble = styled(Link)`
|
||||||
`
|
`
|
||||||
|
|
||||||
type TimelineGroupAlbumProps = {
|
type TimelineGroupAlbumProps = {
|
||||||
group: {
|
dateIndex: number
|
||||||
album: myTimeline_myTimeline_album
|
albumIndex: number
|
||||||
media: myTimeline_myTimeline_media[]
|
mediaState: TimelineGalleryState
|
||||||
mediaTotal: number
|
dispatchMedia: React.Dispatch<TimelineGalleryAction>
|
||||||
}
|
|
||||||
onSelectMedia(index: number): void
|
|
||||||
setPresenting: React.Dispatch<React.SetStateAction<boolean>>
|
|
||||||
activeIndex: number
|
|
||||||
onFavorite(): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelineGroupAlbum = ({
|
const TimelineGroupAlbum = ({
|
||||||
group: { album, media, mediaTotal },
|
dateIndex,
|
||||||
onSelectMedia,
|
albumIndex,
|
||||||
setPresenting,
|
mediaState,
|
||||||
activeIndex,
|
dispatchMedia,
|
||||||
onFavorite,
|
|
||||||
}: TimelineGroupAlbumProps) => {
|
}: TimelineGroupAlbumProps) => {
|
||||||
const { updateSidebar } = useContext(SidebarContext)
|
const { media, mediaTotal, album } = mediaState.timelineGroups[
|
||||||
|
dateIndex
|
||||||
|
].groups[albumIndex]
|
||||||
|
|
||||||
const mediaElms = media.map((media, i) => (
|
const [markFavorite] = useMarkFavoriteMutation()
|
||||||
|
|
||||||
|
const mediaElms = media.map((media, index) => (
|
||||||
<MediaThumbnail
|
<MediaThumbnail
|
||||||
key={media.id}
|
key={media.id}
|
||||||
media={media}
|
media={media}
|
||||||
onSelectImage={index => {
|
selectImage={() => {
|
||||||
onSelectMedia(index)
|
dispatchMedia({
|
||||||
updateSidebar(<MediaSidebar media={media} />)
|
type: 'selectImage',
|
||||||
|
index: {
|
||||||
|
album: albumIndex,
|
||||||
|
date: dateIndex,
|
||||||
|
media: index,
|
||||||
|
},
|
||||||
|
})
|
||||||
}}
|
}}
|
||||||
setPresenting={setPresenting}
|
clickPresent={() => {
|
||||||
onFavorite={onFavorite}
|
openTimelinePresentMode({
|
||||||
index={i}
|
dispatchMedia,
|
||||||
active={activeIndex == i}
|
activeIndex: {
|
||||||
|
album: albumIndex,
|
||||||
|
date: dateIndex,
|
||||||
|
media: index,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
clickFavorite={() => {
|
||||||
|
toggleFavoriteAction({
|
||||||
|
media,
|
||||||
|
markFavorite,
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
active={media.id === getActiveTimelineImage({ mediaState })?.id}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,10 @@ import styled from 'styled-components'
|
||||||
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
import { myTimeline_myTimeline } from './__generated__/myTimeline'
|
||||||
import { TimelineActiveIndex } from './TimelineGallery'
|
import { TimelineActiveIndex } from './TimelineGallery'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import {
|
||||||
|
TimelineGalleryAction,
|
||||||
|
TimelineGalleryState,
|
||||||
|
} from './timelineGalleryReducer'
|
||||||
|
|
||||||
const dateFormatterOptions: Intl.DateTimeFormatOptions = {
|
const dateFormatterOptions: Intl.DateTimeFormatOptions = {
|
||||||
year: 'numeric',
|
year: 'numeric',
|
||||||
|
@ -26,37 +30,27 @@ const GroupAlbumWrapper = styled.div`
|
||||||
`
|
`
|
||||||
|
|
||||||
type TimelineGroupDateProps = {
|
type TimelineGroupDateProps = {
|
||||||
date: string
|
groupIndex: number
|
||||||
groups: myTimeline_myTimeline[]
|
mediaState: TimelineGalleryState
|
||||||
onSelectDateGroup(args: { media: number; albumGroup: number }): void
|
dispatchMedia: React.Dispatch<TimelineGalleryAction>
|
||||||
activeIndex: TimelineActiveIndex
|
|
||||||
setPresenting: React.Dispatch<React.SetStateAction<boolean>>
|
|
||||||
onFavorite(): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelineGroupDate = ({
|
const TimelineGroupDate = ({
|
||||||
date,
|
groupIndex,
|
||||||
groups,
|
mediaState,
|
||||||
onSelectDateGroup,
|
dispatchMedia,
|
||||||
activeIndex,
|
|
||||||
setPresenting,
|
|
||||||
onFavorite,
|
|
||||||
}: TimelineGroupDateProps) => {
|
}: TimelineGroupDateProps) => {
|
||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
|
|
||||||
const albumGroupElms = groups.map((group, i) => (
|
const group = mediaState.timelineGroups[groupIndex]
|
||||||
|
|
||||||
|
const albumGroupElms = group.groups.map((group, i) => (
|
||||||
<TimelineGroupAlbum
|
<TimelineGroupAlbum
|
||||||
key={`${group.date}_${group.album.id}`}
|
key={`${group.date}_${group.album.id}`}
|
||||||
group={group}
|
dateIndex={groupIndex}
|
||||||
onSelectMedia={mediaIndex => {
|
albumIndex={i}
|
||||||
onSelectDateGroup({
|
mediaState={mediaState}
|
||||||
media: mediaIndex,
|
dispatchMedia={dispatchMedia}
|
||||||
albumGroup: i,
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
activeIndex={activeIndex.albumGroup == i ? activeIndex.media : -1}
|
|
||||||
setPresenting={setPresenting}
|
|
||||||
onFavorite={onFavorite}
|
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -65,7 +59,7 @@ const TimelineGroupDate = ({
|
||||||
dateFormatterOptions
|
dateFormatterOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
const formattedDate = dateFormatter.format(new Date(date))
|
const formattedDate = dateFormatter.format(new Date(group.date))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GroupDateWrapper>
|
<GroupDateWrapper>
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
myTimeline_myTimeline,
|
||||||
|
myTimeline_myTimeline_media,
|
||||||
|
} from './__generated__/myTimeline'
|
||||||
|
import { TimelineGroup } from './TimelineGallery'
|
||||||
|
import { UpdateSidebarFn } from '../sidebar/Sidebar'
|
||||||
|
import MediaSidebar from '../sidebar/MediaSidebar'
|
||||||
|
import { GalleryAction } from '../photoGallery/photoGalleryReducer'
|
||||||
|
|
||||||
|
export interface TimelineMediaIndex {
|
||||||
|
date: number
|
||||||
|
album: number
|
||||||
|
media: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TimelineGalleryState {
|
||||||
|
presenting: boolean
|
||||||
|
timelineGroups: TimelineGroup[]
|
||||||
|
activeIndex: TimelineMediaIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TimelineGalleryAction =
|
||||||
|
| GalleryAction
|
||||||
|
| { type: 'replaceTimelineGroups'; timeline: myTimeline_myTimeline[] }
|
||||||
|
| { type: 'selectImage'; index: TimelineMediaIndex }
|
||||||
|
| { type: 'openPresentMode'; activeIndex: TimelineMediaIndex }
|
||||||
|
|
||||||
|
export function timelineGalleryReducer(
|
||||||
|
state: TimelineGalleryState,
|
||||||
|
action: TimelineGalleryAction
|
||||||
|
): TimelineGalleryState {
|
||||||
|
console.log('timeline gallery reducer', state, action)
|
||||||
|
switch (action.type) {
|
||||||
|
case 'replaceTimelineGroups': {
|
||||||
|
const dateGroupedAlbums = action.timeline.reduce((acc, val) => {
|
||||||
|
if (acc.length == 0 || acc[acc.length - 1].date != val.date) {
|
||||||
|
acc.push({
|
||||||
|
date: val.date,
|
||||||
|
groups: [val],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
acc[acc.length - 1].groups.push(val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc
|
||||||
|
}, [] as TimelineGroup[])
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
album: -1,
|
||||||
|
date: -1,
|
||||||
|
media: -1,
|
||||||
|
},
|
||||||
|
timelineGroups: dateGroupedAlbums,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'nextImage': {
|
||||||
|
const { activeIndex, timelineGroups } = state
|
||||||
|
|
||||||
|
const albumGroups = timelineGroups[activeIndex.date].groups
|
||||||
|
const albumMedia = albumGroups[activeIndex.album].media
|
||||||
|
|
||||||
|
if (activeIndex.media < albumMedia.length - 1) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
...state.activeIndex,
|
||||||
|
media: activeIndex.media + 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeIndex.album < albumGroups.length - 1) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
...state.activeIndex,
|
||||||
|
album: activeIndex.album + 1,
|
||||||
|
media: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeIndex.date < timelineGroups.length - 1) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
date: activeIndex.date + 1,
|
||||||
|
album: 0,
|
||||||
|
media: 0,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reached the end
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
case 'previousImage': {
|
||||||
|
const { activeIndex } = state
|
||||||
|
|
||||||
|
if (activeIndex.media > 0) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
...activeIndex,
|
||||||
|
media: activeIndex.media - 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeIndex.album > 0) {
|
||||||
|
const albumGroups = state.timelineGroups[activeIndex.date].groups
|
||||||
|
const albumMedia = albumGroups[activeIndex.album - 1].media
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
...activeIndex,
|
||||||
|
album: activeIndex.album - 1,
|
||||||
|
media: albumMedia.length - 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeIndex.date > 0) {
|
||||||
|
const albumGroups = state.timelineGroups[activeIndex.date - 1].groups
|
||||||
|
const albumMedia = albumGroups[activeIndex.album - 1].media
|
||||||
|
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: {
|
||||||
|
date: activeIndex.date - 1,
|
||||||
|
album: albumGroups.length - 1,
|
||||||
|
media: albumMedia.length - 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// reached the start
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
case 'selectImage': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
activeIndex: action.index,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case 'openPresentMode':
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
presenting: true,
|
||||||
|
activeIndex: action.activeIndex,
|
||||||
|
}
|
||||||
|
case 'closePresentMode': {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
presenting: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getTimelineImage = ({
|
||||||
|
mediaState,
|
||||||
|
index,
|
||||||
|
}: {
|
||||||
|
mediaState: TimelineGalleryState
|
||||||
|
index: TimelineMediaIndex
|
||||||
|
}): myTimeline_myTimeline_media => {
|
||||||
|
const { date, album, media } = index
|
||||||
|
return mediaState.timelineGroups[date].groups[album].media[media]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getActiveTimelineImage = ({
|
||||||
|
mediaState,
|
||||||
|
}: {
|
||||||
|
mediaState: TimelineGalleryState
|
||||||
|
}) => {
|
||||||
|
if (
|
||||||
|
Object.values(mediaState.activeIndex).reduce(
|
||||||
|
(acc, next) => next == -1 || acc,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
return getTimelineImage({ mediaState, index: mediaState.activeIndex })
|
||||||
|
}
|
||||||
|
|
||||||
|
// export const selectTimelineImageAction = ({
|
||||||
|
// index,
|
||||||
|
// mediaState,
|
||||||
|
// dispatchMedia,
|
||||||
|
// updateSidebar,
|
||||||
|
// }: {
|
||||||
|
// index: TimelineMediaIndex
|
||||||
|
// mediaState: TimelineGalleryState
|
||||||
|
// dispatchMedia: React.Dispatch<TimelineGalleryAction>
|
||||||
|
// updateSidebar: UpdateSidebarFn
|
||||||
|
// }) => {
|
||||||
|
// updateSidebar(
|
||||||
|
// <MediaSidebar media={getTimelineImage({ mediaState, index })} />
|
||||||
|
// )
|
||||||
|
// dispatchMedia({
|
||||||
|
// type: 'selectImage',
|
||||||
|
// index,
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
export const openTimelinePresentMode = ({
|
||||||
|
dispatchMedia,
|
||||||
|
activeIndex,
|
||||||
|
}: {
|
||||||
|
dispatchMedia: React.Dispatch<TimelineGalleryAction>
|
||||||
|
activeIndex: TimelineMediaIndex
|
||||||
|
}) => {
|
||||||
|
dispatchMedia({
|
||||||
|
type: 'openPresentMode',
|
||||||
|
activeIndex,
|
||||||
|
})
|
||||||
|
|
||||||
|
history.pushState({ presenting: true, activeIndex: activeIndex }, '')
|
||||||
|
}
|
Loading…
Reference in New Issue