mirror of
https://github.com/jeffvli/feishin.git
synced 2026-07-18 00:16:40 +02:00
fix album group height calculation on index reorder
This commit is contained in:
@@ -31,21 +31,21 @@ import { LibraryItem, Song } from '/@/shared/types/domain-types';
|
||||
import { Play } from '/@/shared/types/types';
|
||||
|
||||
interface AlbumGroupHeaderProps {
|
||||
groupKey?: string;
|
||||
groupRowCount?: number;
|
||||
metadata: AlbumGroupMetadata;
|
||||
onPlay?: (playType: Play) => void;
|
||||
rowIndex?: number;
|
||||
setAlbumGroupContentHeight?: (rowIndex: number, height: number) => void;
|
||||
setAlbumGroupContentHeight?: (groupKey: string, height: number) => void;
|
||||
size?: AlbumGroupTextSize;
|
||||
song: Song | undefined;
|
||||
storedContentHeight?: number;
|
||||
}
|
||||
|
||||
export const AlbumGroupHeader = ({
|
||||
groupKey,
|
||||
groupRowCount,
|
||||
metadata,
|
||||
onPlay,
|
||||
rowIndex,
|
||||
setAlbumGroupContentHeight,
|
||||
size = 'normal',
|
||||
song,
|
||||
@@ -55,7 +55,9 @@ export const AlbumGroupHeader = ({
|
||||
const albumGroupItems = useAlbumGroupItems();
|
||||
const showFavoriteRating = useAlbumGroupShowFavoriteRating();
|
||||
const [isHovered, setIsHovered] = useState(false);
|
||||
const [resolvedInfoHeight, setResolvedInfoHeight] = useState<number | undefined>();
|
||||
const [resolved, setResolved] = useState<null | { forInfoHeight: number; height: number }>(
|
||||
null,
|
||||
);
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
const albumImageSize = useAlbumGroupImageSize();
|
||||
const rowHeight = {
|
||||
@@ -87,6 +89,13 @@ export const AlbumGroupHeader = ({
|
||||
: groupRowCount * rowHeight
|
||||
: undefined;
|
||||
|
||||
// Ignore resolved height from a previous (larger) group span so minHeight
|
||||
// cannot keep scrollHeight measurement stuck after a split/shrink.
|
||||
const resolvedInfoHeight =
|
||||
resolved && infoHeight !== undefined && resolved.forInfoHeight === infoHeight
|
||||
? resolved.height
|
||||
: undefined;
|
||||
|
||||
const imageContainerStyle =
|
||||
albumImageSize > 0
|
||||
? {
|
||||
@@ -108,12 +117,14 @@ export const AlbumGroupHeader = ({
|
||||
|
||||
const measure = () => {
|
||||
const contentHeight = infoEl.scrollHeight;
|
||||
const resolved = Math.max(infoHeight ?? 0, contentHeight);
|
||||
const resolvedHeight = Math.max(infoHeight ?? 0, contentHeight);
|
||||
|
||||
setResolvedInfoHeight(resolved);
|
||||
if (infoHeight !== undefined) {
|
||||
setResolved({ forInfoHeight: infoHeight, height: resolvedHeight });
|
||||
}
|
||||
|
||||
if (rowIndex !== undefined && setAlbumGroupContentHeight) {
|
||||
setAlbumGroupContentHeight(rowIndex, contentHeight);
|
||||
if (groupKey !== undefined && setAlbumGroupContentHeight) {
|
||||
setAlbumGroupContentHeight(groupKey, contentHeight);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -124,9 +135,10 @@ export const AlbumGroupHeader = ({
|
||||
|
||||
return () => resizeObserver.disconnect();
|
||||
}, [
|
||||
groupKey,
|
||||
groupRowCount,
|
||||
infoHeight,
|
||||
metadataRows.length,
|
||||
rowIndex,
|
||||
setAlbumGroupContentHeight,
|
||||
storedContentHeight,
|
||||
]);
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { AlbumGroupHeader } from '/@/renderer/components/item-list/item-table-list/album-group-header';
|
||||
import { computeAlbumGroupMetadata } from '/@/renderer/components/item-list/item-table-list/album-group-metadata';
|
||||
import {
|
||||
getAlbumGroupHeightKey,
|
||||
isLastInAlbumGroup,
|
||||
ItemTableListInnerColumn,
|
||||
TableColumnContainer,
|
||||
@@ -89,6 +90,10 @@ export const AlbumGroupColumn = (props: ItemTableListInnerColumn) => {
|
||||
}
|
||||
|
||||
const metadata = computeAlbumGroupMetadata(groupSongs, groupRowCount, t);
|
||||
const groupHeightKey = getAlbumGroupHeightKey(item, groupRowCount);
|
||||
const storedContentHeight = groupHeightKey
|
||||
? props.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<TableColumnContainer
|
||||
@@ -98,14 +103,14 @@ export const AlbumGroupColumn = (props: ItemTableListInnerColumn) => {
|
||||
isDraggedOver={null}
|
||||
>
|
||||
<AlbumGroupHeader
|
||||
groupKey={groupHeightKey}
|
||||
groupRowCount={groupRowCount}
|
||||
metadata={metadata}
|
||||
onPlay={handlePlay}
|
||||
rowIndex={props.rowIndex}
|
||||
setAlbumGroupContentHeight={props.setAlbumGroupContentHeight}
|
||||
size={props.size === 'default' ? 'normal' : props.size}
|
||||
song={item}
|
||||
storedContentHeight={props.albumGroupContentHeights?.get(props.rowIndex)}
|
||||
storedContentHeight={storedContentHeight}
|
||||
/>
|
||||
</TableColumnContainer>
|
||||
);
|
||||
|
||||
+1
-1
@@ -19,7 +19,7 @@ export const useTableScrollToIndex = ({
|
||||
rowRef,
|
||||
scrollCellProps,
|
||||
}: {
|
||||
albumGroupContentHeights: Map<number, number>;
|
||||
albumGroupContentHeights: Map<string, number>;
|
||||
autoScrollToActiveRow: boolean;
|
||||
enableHeader: boolean;
|
||||
getRowHeight: (index: number, cellProps: TableItemProps) => number;
|
||||
|
||||
@@ -384,6 +384,22 @@ export const ItemTableListColumn = memo(ItemTableListColumnBase, (prevProps, nex
|
||||
|
||||
const NonMutedColumns = [TableColumn.TITLE, TableColumn.TITLE_ARTIST, TableColumn.TITLE_COMBINED];
|
||||
|
||||
/** Stable key for album-group content heights (survives row moves; not row index). */
|
||||
export function getAlbumGroupHeightKey(item: unknown, groupRowCount?: number): string | undefined {
|
||||
if (!item || typeof item !== 'object') return undefined;
|
||||
|
||||
let itemKey: string | undefined;
|
||||
if ('_uniqueId' in item && typeof (item as { _uniqueId?: unknown })._uniqueId === 'string') {
|
||||
itemKey = (item as { _uniqueId: string })._uniqueId;
|
||||
} else if ('id' in item && typeof (item as { id?: unknown }).id === 'string') {
|
||||
itemKey = (item as { id: string }).id;
|
||||
}
|
||||
|
||||
if (!itemKey) return undefined;
|
||||
if (groupRowCount === undefined) return itemKey;
|
||||
return `${itemKey}:${groupRowCount}`;
|
||||
}
|
||||
|
||||
// Counts how many consecutive rows belong to the same album group as `rowIndex`.
|
||||
export function getAlbumGroupRowCount(
|
||||
rowIndex: number,
|
||||
@@ -550,7 +566,10 @@ function getAlbumGroupClampHeight(props: ItemTableListInnerColumn): null | numbe
|
||||
props.getRowItem,
|
||||
props.enableHeader,
|
||||
);
|
||||
const contentHeight = props.albumGroupContentHeights?.get(groupStartRowIndex) ?? 0;
|
||||
const groupStartItem = props.getRowItem?.(groupStartRowIndex);
|
||||
const groupHeightKey = getAlbumGroupHeightKey(groupStartItem, groupRowCount);
|
||||
const contentHeight =
|
||||
(groupHeightKey ? props.albumGroupContentHeights?.get(groupHeightKey) : undefined) ?? 0;
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
|
||||
@@ -45,6 +45,7 @@ import { useTablePaneSync } from '/@/renderer/components/item-list/item-table-li
|
||||
import { useTableRowModel } from '/@/renderer/components/item-list/item-table-list/hooks/use-table-row-model';
|
||||
import { useTableScrollToIndex } from '/@/renderer/components/item-list/item-table-list/hooks/use-table-scroll-to-index';
|
||||
import {
|
||||
getAlbumGroupHeightKey,
|
||||
getAlbumGroupRowCount,
|
||||
getAlbumGroupSpanHeight,
|
||||
getAlbumGroupStartRowIndex,
|
||||
@@ -176,7 +177,7 @@ const ItemTableScrollShadowRight = memo(function ItemTableScrollShadowRight({
|
||||
ItemTableScrollShadowRight.displayName = 'ItemTableScrollShadowRight';
|
||||
|
||||
interface VirtualizedTableGridProps {
|
||||
albumGroupContentHeights: Map<number, number>;
|
||||
albumGroupContentHeights: Map<string, number>;
|
||||
calculatedColumnWidths: number[];
|
||||
CellComponent: JSXElementConstructor<CellComponentProps<TableItemProps>>;
|
||||
data: unknown[];
|
||||
@@ -194,7 +195,7 @@ interface VirtualizedTableGridProps {
|
||||
pinnedRowCount: number;
|
||||
pinnedRowRef: React.RefObject<HTMLDivElement | null>;
|
||||
scrollShadowStore: TableScrollShadowStore;
|
||||
setAlbumGroupContentHeight: (rowIndex: number, height: number) => void;
|
||||
setAlbumGroupContentHeight: (groupKey: string, height: number) => void;
|
||||
tableConfig: ItemTableListConfig;
|
||||
totalColumnCount: number;
|
||||
totalRowCount: number;
|
||||
@@ -773,7 +774,7 @@ export interface TableGroupHeader {
|
||||
|
||||
export interface TableItemProps {
|
||||
adjustedRowIndexMap?: Map<number, number>;
|
||||
albumGroupContentHeights?: Map<number, number>;
|
||||
albumGroupContentHeights?: Map<string, number>;
|
||||
albumGroupImageSize?: number;
|
||||
calculatedColumnWidths?: number[];
|
||||
cellPadding?: ItemTableListProps['cellPadding'];
|
||||
@@ -807,7 +808,7 @@ export interface TableItemProps {
|
||||
pinnedRightColumnWidths?: number[];
|
||||
playerContext: PlayerContext;
|
||||
playlistId?: string;
|
||||
setAlbumGroupContentHeight?: (rowIndex: number, height: number) => void;
|
||||
setAlbumGroupContentHeight?: (groupKey: string, height: number) => void;
|
||||
size?: ItemTableListProps['size'];
|
||||
startRowIndex?: number;
|
||||
tableId: string;
|
||||
@@ -1298,14 +1299,14 @@ const BaseItemTableList = ({
|
||||
const albumGroupImageSize = useAlbumGroupImageSize();
|
||||
const baseItemCount = itemCount ?? data.length;
|
||||
const [albumGroupContentHeights, setAlbumGroupContentHeights] = useState(
|
||||
() => new Map<number, number>(),
|
||||
() => new Map<string, number>(),
|
||||
);
|
||||
|
||||
const setAlbumGroupContentHeight = useCallback((rowIndex: number, height: number) => {
|
||||
const setAlbumGroupContentHeight = useCallback((groupKey: string, height: number) => {
|
||||
setAlbumGroupContentHeights((prev) => {
|
||||
if (prev.get(rowIndex) === height) return prev;
|
||||
if (prev.get(groupKey) === height) return prev;
|
||||
const next = new Map(prev);
|
||||
next.set(rowIndex, height);
|
||||
next.set(groupKey, height);
|
||||
return next;
|
||||
});
|
||||
}, []);
|
||||
@@ -1460,8 +1461,12 @@ const BaseItemTableList = ({
|
||||
cellProps.getRowItem,
|
||||
cellProps.enableHeader,
|
||||
);
|
||||
const groupStartItem = cellProps.getRowItem?.(groupStartRowIndex);
|
||||
const groupHeightKey = getAlbumGroupHeightKey(groupStartItem, groupRowCount);
|
||||
const contentHeight =
|
||||
cellProps.albumGroupContentHeights?.get(groupStartRowIndex) ?? 0;
|
||||
(groupHeightKey
|
||||
? cellProps.albumGroupContentHeights?.get(groupHeightKey)
|
||||
: undefined) ?? 0;
|
||||
const totalGroupHeight = getAlbumGroupSpanHeight(
|
||||
groupRowCount,
|
||||
baseHeight,
|
||||
|
||||
Reference in New Issue
Block a user