mirror of
https://github.com/Ernous/TorrServerJellyfin.git
synced 2025-12-19 21:46:11 +05:00
118 lines
4.0 KiB
JavaScript
118 lines
4.0 KiB
JavaScript
import Measure from 'react-measure'
|
|
import { useState, memo, useRef, useEffect } from 'react'
|
|
import { useTranslation } from 'react-i18next'
|
|
import isEqual from 'lodash/isEqual'
|
|
|
|
import { useCreateCacheMap } from '../customHooks'
|
|
import getShortCacheMap from './getShortCacheMap'
|
|
import { SnakeWrapper, ScrollNotification } from './style'
|
|
import {
|
|
defaultBorderWidth,
|
|
miniCacheMaxHeight,
|
|
pieceSizeForMiniMap,
|
|
defaultPieceSize,
|
|
defaultBackgroundColor,
|
|
defaultBorderColor,
|
|
completeColor,
|
|
activeColor,
|
|
rangeColor,
|
|
defaultGapBetweenPieces,
|
|
miniBackgroundColor,
|
|
miniBorderWidth,
|
|
miniGapBetweenPieces,
|
|
createGradient,
|
|
} from './snakeSettings'
|
|
|
|
const TorrentCache = ({ cache, isMini }) => {
|
|
const { t } = useTranslation()
|
|
const [dimensions, setDimensions] = useState({ width: 0, height: 0 })
|
|
const { width } = dimensions
|
|
const canvasRef = useRef(null)
|
|
const ctxRef = useRef(null)
|
|
const cacheMap = useCreateCacheMap(cache)
|
|
|
|
const canvasWidth = isMini ? width * 0.93 : width
|
|
const pieceSize = isMini ? pieceSizeForMiniMap : defaultPieceSize
|
|
const gapBetweenPieces = isMini ? miniGapBetweenPieces : defaultGapBetweenPieces
|
|
|
|
const pieceSizeWithGap = pieceSize + gapBetweenPieces
|
|
const piecesInOneRow = Math.floor(canvasWidth / pieceSizeWithGap)
|
|
|
|
let shotCacheMap
|
|
if (isMini) {
|
|
const preloadPiecesAmount = Math.round(cache.Capacity / cache.PiecesLength - 1)
|
|
shotCacheMap = getShortCacheMap({ cacheMap, preloadPiecesAmount, piecesInOneRow })
|
|
}
|
|
const source = isMini ? shotCacheMap : cacheMap
|
|
const startingXPoint = Math.ceil((canvasWidth - pieceSizeWithGap * piecesInOneRow) / 2) // needed to center grid
|
|
const height = Math.ceil(source.length / piecesInOneRow) * pieceSizeWithGap
|
|
|
|
useEffect(() => {
|
|
if (!canvasWidth || !height) return
|
|
|
|
const canvas = canvasRef.current
|
|
canvas.width = canvasWidth
|
|
canvas.height = height
|
|
ctxRef.current = canvas.getContext('2d')
|
|
}, [canvasRef, height, canvasWidth])
|
|
|
|
useEffect(() => {
|
|
const ctx = ctxRef.current
|
|
if (!ctx) return
|
|
|
|
ctx.clearRect(0, 0, canvasWidth, height)
|
|
|
|
source.forEach(({ percentage, isReader, isReaderRange }, i) => {
|
|
const inProgress = percentage > 0 && percentage < 100
|
|
const isCompleted = percentage === 100
|
|
const currentRow = i % piecesInOneRow
|
|
const currentColumn = Math.floor(i / piecesInOneRow)
|
|
const borderWidth = isMini ? miniBorderWidth : defaultBorderWidth
|
|
const fixBlurStroke = borderWidth % 2 === 0 ? 0 : 0.5
|
|
const requiredFix = Math.ceil(borderWidth / 2) + 1 + fixBlurStroke
|
|
const x = currentRow * pieceSize + currentRow * gapBetweenPieces + startingXPoint + requiredFix
|
|
const y = currentColumn * pieceSize + currentColumn * gapBetweenPieces + requiredFix
|
|
|
|
ctx.lineWidth = borderWidth
|
|
ctx.fillStyle = inProgress
|
|
? createGradient(ctx, percentage, pieceSize)
|
|
: isCompleted
|
|
? completeColor
|
|
: isMini
|
|
? miniBackgroundColor
|
|
: defaultBackgroundColor
|
|
ctx.strokeStyle = isReader
|
|
? activeColor
|
|
: inProgress || isCompleted
|
|
? completeColor
|
|
: isReaderRange
|
|
? rangeColor
|
|
: defaultBorderColor
|
|
|
|
ctx.translate(x, y)
|
|
ctx.fillRect(0, 0, pieceSize, pieceSize)
|
|
ctx.strokeRect(0, 0, pieceSize, pieceSize)
|
|
ctx.setTransform(1, 0, 0, 1, 0, 0)
|
|
})
|
|
}, [cacheMap, height, canvasWidth, piecesInOneRow, isMini, startingXPoint, pieceSize, gapBetweenPieces, source])
|
|
|
|
return (
|
|
<Measure bounds onResize={({ bounds }) => setDimensions(bounds)}>
|
|
{({ measureRef }) => (
|
|
<div style={{ display: 'flex', flexDirection: 'column' }} ref={measureRef}>
|
|
<SnakeWrapper isMini={isMini}>
|
|
<canvas ref={canvasRef} />
|
|
</SnakeWrapper>
|
|
|
|
{isMini && height >= miniCacheMaxHeight && <ScrollNotification>{t('ScrollDown')}</ScrollNotification>}
|
|
</div>
|
|
)}
|
|
</Measure>
|
|
)
|
|
}
|
|
|
|
export default memo(
|
|
TorrentCache,
|
|
(prev, next) => isEqual(prev.cache.Pieces, next.cache.Pieces) && isEqual(prev.cache.Readers, next.cache.Readers),
|
|
)
|