Skip to content

Commit

Permalink
Fix image pack loading (#288)
Browse files Browse the repository at this point in the history
* Fixes display of the image packs

* Also prevent text overlaps in the data packs

* Only load the platforms / image packs that're on screen
  • Loading branch information
neil-morrison44 authored May 19, 2024
1 parent 91bb882 commit bc86f73
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 87 deletions.
1 change: 0 additions & 1 deletion src-tauri/src/file_locks/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use futures_locks::{RwLockReadGuard, RwLockWriteGuard};
use std::sync::Arc;
use std::{collections::HashMap, path::PathBuf};
use tokio::sync::RwLock;
Expand Down
3 changes: 1 addition & 2 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ use saves_zip::{
remove_leading_slash, restore_save_from_zip, SaveZipFile,
};
use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::path::PathBuf;
use std::time::SystemTime;
use std::vec;
use tauri::api::dialog;
Expand Down
3 changes: 2 additions & 1 deletion src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
"https://raw.githubusercontent.com/*",
"https://archive.org/*",
"https://updater.retrodriven.com/*",
"https://objects.githubusercontent.com/*"
"https://objects.githubusercontent.com/*",
"https://neil-morrison44.github.io/*"
]
},
"fs": {
Expand Down
43 changes: 2 additions & 41 deletions src/components/grid/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import {
Children,
MutableRefObject,
ReactNode,
useEffect,
useRef,
useState,
} from "react"
import { Children, ReactNode } from "react"
import "./index.css"
import { OnlyLoadsWhenShown } from "../../utils/onlyLoadsWhenShown"

type GridProps = {
children: ReactNode
Expand All @@ -33,36 +27,3 @@ export const Grid = ({
</div>
)
}

const OnlyLoadsWhenShown = ({
height,
children,
}: {
height: number
children: ReactNode
}) => {
const placeHolderDivRef = useRef<HTMLDivElement>(null)
const hasBeenShown = useHasBeenShown(placeHolderDivRef)
if (!hasBeenShown)
return <div ref={placeHolderDivRef} style={{ height: `${height}px` }}></div>
return <>{children}</>
}

const useHasBeenShown = (element: MutableRefObject<HTMLElement | null>) => {
const [hasBeenShown, setState] = useState(false)
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting && element.current) {
setState(true)
observer.unobserve(element.current)
}
})

const node = element.current
node && observer.observe(node)
return () => {
node && observer.unobserve(node)
}
}, [element])
return hasBeenShown
}
4 changes: 2 additions & 2 deletions src/components/platforms/dataPacks/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

.data-packs__pack-item{
flex-basis: max-content;
line-break: anywhere;
}

.data-packs__current-item, .data-packs__pack-item{
Expand All @@ -39,7 +40,6 @@
width: 100%;
display: flex;
flex-direction: column;
justify-items: stretch;
align-items: stretch;
place-items: stretch stretch;
gap: 20px;
}
97 changes: 60 additions & 37 deletions src/components/platforms/imagePacks/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { Suspense, useMemo, useState } from "react"
import { useRecoilCallback, useRecoilValue } from "recoil"
import {
useRecoilCallback,
useRecoilValue,
useRecoilValueLoadable,
} from "recoil"
import { pocketPathAtom } from "../../../recoil/atoms"
import {
ImagePackImageSelectorFamily,
Expand All @@ -16,6 +20,7 @@ import { useTranslation } from "react-i18next"

import "./index.css"
import { PlatformName } from "./platformName"
import { OnlyLoadsWhenShown } from "../../../utils/onlyLoadsWhenShown"

type ImagePacksProps = {
onClose: () => void
Expand All @@ -29,7 +34,13 @@ export const ImagePacks = ({ onClose, singlePlatformId }: ImagePacksProps) => {
return allPlatformIds
}, [allPlatformIds, singlePlatformId])

const imagePacks = useRecoilValue(imagePackListSelector)
const imagePacksLoadable = useRecoilValueLoadable(imagePackListSelector)

const imagePacks = useMemo(() => {
if (imagePacksLoadable.state !== "hasValue") return []
return imagePacksLoadable.contents
}, [imagePacksLoadable])

const [selections, setSelections] = useState<
Record<PlatformId, ImagePack | undefined>
>({})
Expand Down Expand Up @@ -77,47 +88,59 @@ export const ImagePacks = ({ onClose, singlePlatformId }: ImagePacksProps) => {
}`}
onClick={() => setSelections((s) => ({ ...s, [pId]: undefined }))}
>
<PlatformName platformId={pId} />
<PlatformImage platformId={pId} className="image-packs__image" />
<OnlyLoadsWhenShown height={103}>
<Suspense>
<PlatformName platformId={pId} />
<PlatformImage
platformId={pId}
className="image-packs__image"
/>
</Suspense>
</OnlyLoadsWhenShown>
</div>
))}
</div>

{imagePacks.map((pack) => (
<div
key={`${pack.owner}-${pack.repository}-${pack.variant}`}
className="image-packs__column"
>
<div className="image-packs__column-name">
<Link
href={`https://github.com/${pack.owner}/${pack.repository}`}
>
<b>{pack.owner}</b>
<div title={pack.repository}>{pack.repository}</div>
{pack.variant && <small>{pack.variant}</small>}
</Link>
</div>
<Suspense key={`${pack.owner}-${pack.repository}-${pack.variant}`}>
<div className="image-packs__column">
<div className="image-packs__column-name">
<Link
href={`https://github.com/${pack.owner}/${pack.repository}`}
>
<b>{pack.owner}</b>
<div title={pack.repository}>{pack.repository}</div>
<small title={pack.variant}>{pack.variant}</small>
</Link>
</div>

{platformIds.map((pId) => (
<Suspense
key={`${pId}-${pack.owner}-${pack.repository}-${pack.variant}`}
fallback={
<div className="image-packs__item image-packs__item--missing">
<Loader />
</div>
}
>
<PackColumnItem
{...pack}
platformId={pId}
onClick={() => setSelections((s) => ({ ...s, [pId]: pack }))}
isSelected={
JSON.stringify(selections[pId]) === JSON.stringify(pack)
}
/>
</Suspense>
))}
</div>
{platformIds.map((pId) => (
<OnlyLoadsWhenShown
key={`${pId}-${pack.owner}-${pack.repository}-${pack.variant}`}
height={103}
>
<Suspense
fallback={
<div className="image-packs__item image-packs__item--missing">
<Loader />
</div>
}
>
<PackColumnItem
{...pack}
platformId={pId}
onClick={() =>
setSelections((s) => ({ ...s, [pId]: pack }))
}
isSelected={
JSON.stringify(selections[pId]) === JSON.stringify(pack)
}
/>
</Suspense>
</OnlyLoadsWhenShown>
))}
</div>
</Suspense>
))}
</div>

Expand Down
4 changes: 2 additions & 2 deletions src/recoil/platforms/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,9 +128,9 @@ export const imagePackListSelector = selector<ImagePack[]>({
responseType: ResponseType.JSON,
}
)

return response.data
} catch (e) {
} catch (err) {
console.error(err)
return []
}
},
Expand Down
2 changes: 1 addition & 1 deletion src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ export type FetchFileMetadataWithStatus = {
export type ImagePack = {
owner: string
repository: string
variant?: string
variant: string
}

export type RawFeedItem = {
Expand Down
34 changes: 34 additions & 0 deletions src/utils/onlyLoadsWhenShown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { MutableRefObject, ReactNode, useEffect, useRef, useState } from "react"

export const OnlyLoadsWhenShown = ({
height,
children,
}: {
height: number
children: ReactNode
}) => {
const placeHolderDivRef = useRef<HTMLDivElement>(null)
const hasBeenShown = useHasBeenShown(placeHolderDivRef)
if (!hasBeenShown)
return <div ref={placeHolderDivRef} style={{ height: `${height}px` }}></div>
return <>{children}</>
}

const useHasBeenShown = (element: MutableRefObject<HTMLElement | null>) => {
const [hasBeenShown, setState] = useState(false)
useEffect(() => {
const observer = new IntersectionObserver(([entry]) => {
if (entry.isIntersecting && element.current) {
setState(true)
observer.unobserve(element.current)
}
})

const node = element.current
node && observer.observe(node)
return () => {
node && observer.unobserve(node)
}
}, [element])
return hasBeenShown
}

0 comments on commit bc86f73

Please sign in to comment.