* feat(artwork): add KindRadioArtwork and EntityRadio constant * feat(model): add UploadedImage field and artwork methods to Radio * feat(model): add Radio to GetEntityByID lookup chain * feat(db): add uploaded_image column to radio table * feat(artwork): add radio artwork reader with uploaded image fallback * feat(api): add radio image upload/delete endpoints * feat(ui): add radio artwork ID prefix to getCoverArtUrl * feat(ui): add cover art display and upload to RadioEdit * feat(ui): add cover art thumbnails to radio list * feat(ui): prefer artwork URL in radio player helper * refactor: remove redundant code in radio artwork - Remove duplicate Avatar rendering in RadioList by reusing CoverArtField - Remove redundant UpdatedAt assignment in radio image handlers (already set by repository Put) * refactor(ui): extract shared useImageLoadingState hook Move image loading/error/lightbox state management into a shared useImageLoadingState hook in common/. Consolidates duplicated logic from AlbumDetails, PlaylistDetails, RadioEdit, and artist detail views. * feat(ui): use radio placeholder icon when no uploaded image Remove album placeholder fallback from radio artwork reader so radios without an uploaded image return ErrUnavailable. On the frontend, show the internet-radio-icon.svg placeholder instead of requesting server artwork when no image is uploaded, allowing favicon fallback in the player. * refactor(ui): update defaultOff fields in useSelectedFields for RadioList Signed-off-by: Deluan <deluan@navidrome.org> * fix: address code review feedback - Add missing alt attribute to CardMedia in RadioEdit for accessibility - Fix UpdateInternetRadio to preserve UploadedImage field by fetching existing radio before updating (prevents Subsonic API from clearing custom artwork) - Add Reader() level tests to verify ErrUnavailable is returned when radio has no uploaded image * refactor: add colsToUpdate to RadioRepository.Put Use the base sqlRepository.put with column filtering instead of hand-rolled SQL. UpdateInternetRadio now specifies only the Subsonic API fields, preventing UploadedImage from being cleared. Image upload/delete handlers specify only UploadedImage. * fix: ensure UpdatedAt is included in colsToUpdate for radio Put --------- Signed-off-by: Deluan <deluan@navidrome.org>
44 lines
1 KiB
JavaScript
44 lines
1 KiB
JavaScript
import { useState, useEffect, useCallback } from 'react'
|
|
|
|
/**
|
|
* Manages image loading/error state and lightbox open/close.
|
|
* Resets when recordId changes.
|
|
*/
|
|
export const useImageLoadingState = (recordId) => {
|
|
const [imageLoading, setImageLoading] = useState(true)
|
|
const [imageError, setImageError] = useState(false)
|
|
const [isLightboxOpen, setLightboxOpen] = useState(false)
|
|
|
|
useEffect(() => {
|
|
setImageLoading(true)
|
|
setImageError(false)
|
|
}, [recordId])
|
|
|
|
const handleImageLoad = useCallback(() => {
|
|
setImageLoading(false)
|
|
setImageError(false)
|
|
}, [])
|
|
|
|
const handleImageError = useCallback(() => {
|
|
setImageLoading(false)
|
|
setImageError(true)
|
|
}, [])
|
|
|
|
const handleOpenLightbox = useCallback(() => {
|
|
if (!imageError) {
|
|
setLightboxOpen(true)
|
|
}
|
|
}, [imageError])
|
|
|
|
const handleCloseLightbox = useCallback(() => setLightboxOpen(false), [])
|
|
|
|
return {
|
|
imageLoading,
|
|
imageError,
|
|
isLightboxOpen,
|
|
handleImageLoad,
|
|
handleImageError,
|
|
handleOpenLightbox,
|
|
handleCloseLightbox,
|
|
}
|
|
}
|