Fix lightbox issues (#2457)

* Don't convert localforage to json
* Show correct delay value
* Fix lightbox delay
* Fix delay input losing focus on change
* Fix delay input inconsistencies
* Fix clicking link preventing scroll bars appearing
* Fix slideshow stopping when paging
This commit is contained in:
WithoutPants
2022-04-04 06:27:18 +10:00
committed by GitHub
parent 6ebf3ddc9e
commit 92320b3418
5 changed files with 156 additions and 140 deletions

View File

@@ -1,3 +1,5 @@
##### 💥 Note: Image Slideshow Delay (in Interface Settings) is now in seconds rather than milliseconds and has not been converted. Please adjust your settings as needed.
### ✨ New Features
* Add python location in System Settings for script scrapers and plugins. ([#2409](https://github.com/stashapp/stash/pull/2409))

View File

@@ -65,6 +65,8 @@ interface IImageListImages {
onChangePage: (page: number) => void;
pageCount: number;
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void;
slideshowRunning: boolean;
setSlideshowRunning: (running: boolean) => void;
}
const ImageListImages: React.FC<IImageListImages> = ({
@@ -74,8 +76,9 @@ const ImageListImages: React.FC<IImageListImages> = ({
onChangePage,
pageCount,
onSelectChange,
slideshowRunning,
setSlideshowRunning,
}) => {
const [slideshowRunning, setSlideshowRunning] = useState<boolean>(false);
const handleLightBoxPage = useCallback(
(direction: number) => {
if (direction === -1) {
@@ -125,7 +128,7 @@ const ImageListImages: React.FC<IImageListImages> = ({
setSlideshowRunning(true);
showLightbox(index, true);
},
[showLightbox]
[showLightbox, setSlideshowRunning]
);
function onPreview(index: number, ev: MouseEvent) {
@@ -197,6 +200,7 @@ export const ImageList: React.FC<IImageList> = ({
const history = useHistory();
const [isExportDialogOpen, setIsExportDialogOpen] = useState(false);
const [isExportAll, setIsExportAll] = useState(false);
const [slideshowRunning, setSlideshowRunning] = useState<boolean>(false);
const otherOperations = (extraOperations ?? []).concat([
{
@@ -336,6 +340,8 @@ export const ImageList: React.FC<IImageList> = ({
onSelectChange={selectChange}
pageCount={pageCount}
selectedIds={selectedIds}
slideshowRunning={slideshowRunning}
setSlideshowRunning={setSlideshowRunning}
/>
);
}

View File

@@ -147,10 +147,16 @@ export const LightboxComponent: React.FC<IProps> = ({
setLightboxSettings({ scrollMode: v });
}
const configuredDelay = config?.interface.imageLightbox.slideshowDelay
? config.interface.imageLightbox.slideshowDelay * SECONDS_TO_MS
: undefined;
const savedDelay = lightboxSettings?.slideshowDelay
? lightboxSettings.slideshowDelay * SECONDS_TO_MS
: undefined;
const slideshowDelay =
lightboxSettings?.slideshowDelay ??
config?.interface.imageLightbox.slideshowDelay ??
DEFAULT_SLIDESHOW_DELAY;
savedDelay ?? configuredDelay ?? DEFAULT_SLIDESHOW_DELAY;
function setSlideshowDelay(v: number) {
setLightboxSettings({ slideshowDelay: v });
@@ -175,7 +181,7 @@ export const LightboxComponent: React.FC<IProps> = ({
const [
displayedSlideshowInterval,
setDisplayedSlideshowInterval,
] = useState<string>(slideshowDelay.toString());
] = useState<string>((slideshowDelay / SECONDS_TO_MS).toString());
useEffect(() => {
if (images !== oldImages.current && isSwitchingPage) {
@@ -264,7 +270,7 @@ export const LightboxComponent: React.FC<IProps> = ({
if (slideshowInterval) {
setSlideshowInterval(null);
} else {
setSlideshowInterval(slideshowDelay * SECONDS_TO_MS);
setSlideshowInterval(slideshowDelay);
}
}, [slideshowInterval, slideshowDelay]);
@@ -409,7 +415,7 @@ export const LightboxComponent: React.FC<IProps> = ({
? numberValue
: MIN_VALID_INTERVAL_SECONDS;
setSlideshowDelay(numberValue * SECONDS_TO_MS);
setSlideshowDelay(numberValue);
if (slideshowInterval !== null) {
setSlideshowInterval(numberValue * SECONDS_TO_MS);
@@ -418,7 +424,11 @@ export const LightboxComponent: React.FC<IProps> = ({
const currentIndex = index === null ? initialIndex : index;
const OptionsForm: React.FC<{}> = () => (
// #2451: making OptionsForm an inline component means it
// get re-rendered each time. This makes the text
// field lose focus on input. Use function instead.
function renderOptionsForm() {
return (
<>
{slideshowEnabled ? (
<Form.Group controlId="delay" as={Row} className="form-container">
@@ -455,13 +465,15 @@ export const LightboxComponent: React.FC<IProps> = ({
value={displayMode}
className="btn-secondary mx-1 mb-1"
>
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map((v) => (
{Array.from(imageLightboxDisplayModeIntlMap.entries()).map(
(v) => (
<option key={v[0]} value={v[0]}>
{intl.formatMessage({
id: v[1],
})}
</option>
))}
)
)}
</Form.Control>
</Col>
</Form.Group>
@@ -513,7 +525,8 @@ export const LightboxComponent: React.FC<IProps> = ({
setScrollMode(e.target.value as GQL.ImageLightboxScrollMode)
}
value={
lightboxSettings?.scrollMode ?? GQL.ImageLightboxScrollMode.Zoom
lightboxSettings?.scrollMode ??
GQL.ImageLightboxScrollMode.Zoom
}
className="btn-secondary mx-1 mb-1"
>
@@ -544,19 +557,7 @@ export const LightboxComponent: React.FC<IProps> = ({
</Form.Group>
</>
);
const optionsPopover = (
<>
<Popover.Title>
{intl.formatMessage({
id: "dialogs.lightbox.options",
})}
</Popover.Title>
<Popover.Content>
<OptionsForm />
</Popover.Content>
</>
);
}
if (!isVisible) {
return <></>;
@@ -650,13 +651,18 @@ export const LightboxComponent: React.FC<IProps> = ({
{...props}
style={{ ...props.style }}
>
{optionsPopover}
<Popover.Title>
{intl.formatMessage({
id: "dialogs.lightbox.options",
})}
</Popover.Title>
<Popover.Content>{renderOptionsForm()}</Popover.Content>
</div>
)}
</Overlay>
</div>
<InputGroup className={CLASSNAME_OPTIONS_INLINE}>
<OptionsForm />
{renderOptionsForm()}
</InputGroup>
</div>
{slideshowEnabled && (
@@ -787,7 +793,7 @@ export const LightboxComponent: React.FC<IProps> = ({
</div>
<div>
{currentImage?.title && (
<Link to={`/images/${currentImage.id}`} onClick={() => hide()}>
<Link to={`/images/${currentImage.id}`} onClick={() => close()}>
{currentImage.title ?? ""}
</Link>
)}

View File

@@ -40,9 +40,11 @@ export function useLocalForage<T>(
useEffect(() => {
async function runAsync() {
try {
const serialized = await localForage.getItem<string>(key);
const parsed = JSON.parse(serialized ?? "null");
if (!Object.is(parsed, null)) {
let parsed = await localForage.getItem<T>(key);
if (typeof parsed === "string") {
parsed = JSON.parse(parsed ?? "null");
}
if (parsed !== null) {
setData(parsed);
Cache[key] = parsed;
} else {
@@ -72,7 +74,7 @@ export function useLocalForage<T>(
...Cache[key],
...data,
};
localForage.setItem(key, JSON.stringify(Cache[key]));
localForage.setItem(key, Cache[key]);
}
});

View File

@@ -524,7 +524,7 @@
},
"slideshow_delay": {
"description": "Slideshow is available in galleries when in wall view mode",
"heading": "Slideshow Delay"
"heading": "Slideshow Delay (seconds)"
},
"title": "User Interface"
}