From 20eae57e7530472186804b760f7da8cd2fd666c4 Mon Sep 17 00:00:00 2001
From: Utku <74243531+utkubakir@users.noreply.github.com>
Date: Mon, 17 Jul 2023 14:47:57 +0300
Subject: [PATCH] [MOB-34] Update thumb logic (#1100)
update thumb logic
---
.../src/components/explorer/FileThumb.tsx | 191 +++++++++++-------
.../settings/client/GeneralSettings.tsx | 16 +-
apps/mobile/src/stores/explorerStore.ts | 2 +-
packages/client/src/hooks/useThemeStore.ts | 4 +
4 files changed, 137 insertions(+), 76 deletions(-)
diff --git a/apps/mobile/src/components/explorer/FileThumb.tsx b/apps/mobile/src/components/explorer/FileThumb.tsx
index 0a5845e79..3a6b92a17 100644
--- a/apps/mobile/src/components/explorer/FileThumb.tsx
+++ b/apps/mobile/src/components/explorer/FileThumb.tsx
@@ -1,10 +1,53 @@
-import * as icons from '@sd/assets/icons';
-import { PropsWithChildren } from 'react';
+import { getIcon } from '@sd/assets/util';
+import { PropsWithChildren, useEffect, useLayoutEffect, useMemo, useState } from 'react';
import { Image, View } from 'react-native';
import { DocumentDirectoryPath } from 'react-native-fs';
-import { ExplorerItem, ObjectKind, getItemFilePath, getItemObject, isPath } from '@sd/client';
+import {
+ ExplorerItem,
+ getExplorerItemData,
+ getItemFilePath,
+ getItemLocation,
+ isDarkTheme
+} from '@sd/client';
+import { flattenThumbnailKey, useExplorerStore } from '~/stores/explorerStore';
import { tw } from '../../lib/tailwind';
-import FolderIcon from '../icons/FolderIcon';
+
+export const getThumbnailUrlByThumbKey = (thumbKey: string[]) =>
+ `${DocumentDirectoryPath}/thumbnails/${thumbKey
+ .map((i) => encodeURIComponent(i))
+ .join('/')}.webp`;
+
+const FileThumbWrapper = ({ children, size = 1 }: PropsWithChildren<{ size: number }>) => (
+
+ {children}
+
+);
+
+function useExplorerItemData(explorerItem: ExplorerItem) {
+ const explorerStore = useExplorerStore();
+
+ const newThumbnail = !!(
+ explorerItem.thumbnail_key &&
+ explorerStore.newThumbnails.has(flattenThumbnailKey(explorerItem.thumbnail_key))
+ );
+
+ return useMemo(() => {
+ const itemData = getExplorerItemData(explorerItem);
+
+ if (!itemData.hasLocalThumbnail) {
+ itemData.hasLocalThumbnail = newThumbnail;
+ }
+
+ return itemData;
+ }, [explorerItem, newThumbnail]);
+}
+
+enum ThumbType {
+ Icon,
+ // Original,
+ Thumbnail,
+ Location
+}
type FileThumbProps = {
data: ExplorerItem;
@@ -13,87 +56,87 @@ type FileThumbProps = {
* default: `1`
*/
size?: number;
+ // loadOriginal?: boolean;
};
-export const getThumbnailUrlById = (keyParts: string[]) =>
- `${DocumentDirectoryPath}/thumbnails/${keyParts
- .map((i) => encodeURIComponent(i))
- .join('/')}.webp`;
+export default function FileThumb({ size = 1, ...props }: FileThumbProps) {
+ const itemData = useExplorerItemData(props.data);
+ const locationData = getItemLocation(props.data);
+ const filePath = getItemFilePath(props.data);
-type KindType = keyof typeof icons | 'Unknown';
+ const [src, setSrc] = useState(null);
+ const [thumbType, setThumbType] = useState(ThumbType.Icon);
+ // const [loaded, setLoaded] = useState(false);
-function getExplorerItemData(data: ExplorerItem) {
- const objectData = getItemObject(data);
- const filePath = getItemFilePath(data);
+ useLayoutEffect(() => {
+ // Reset src when item changes, to allow detection of yet not updated src
+ setSrc(null);
+ // setLoaded(false);
- return {
- casId: filePath?.cas_id || null,
- isDir: isPath(data) && data.item.is_dir,
- kind: ObjectKind[objectData?.kind || 0] as KindType,
- hasLocalThumbnail: data.has_local_thumbnail, // this will be overwritten if new thumbnail is generated
- thumbnailKey: data.thumbnail_key,
- extension: filePath?.extension
- };
-}
+ if (locationData) {
+ setThumbType(ThumbType.Location);
+ // } else if (props.loadOriginal) {
+ // setThumbType(ThumbType.Original);
+ } else if (itemData.hasLocalThumbnail) {
+ setThumbType(ThumbType.Thumbnail);
+ } else {
+ setThumbType(ThumbType.Icon);
+ }
+ }, [locationData, itemData]);
-const FileThumbWrapper = ({ children, size = 1 }: PropsWithChildren<{ size: number }>) => (
-
- {children}
-
-);
+ // This sets the src to the thumbnail url
+ useEffect(() => {
+ const { casId, kind, isDir, extension, locationId, thumbnailKey } = itemData;
-export default function FileThumb({ data, size = 1 }: FileThumbProps) {
- const { casId, isDir, kind, hasLocalThumbnail, extension, thumbnailKey } =
- getExplorerItemData(data);
+ // ???
+ // const locationId =
+ // itemLocationId ?? (parent?.type === 'Location' ? parent.location.id : null);
- if (isPath(data) && data.item.is_dir) {
- return (
-
-
-
- );
- }
-
- if (hasLocalThumbnail && thumbnailKey) {
- // TODO: Handle Image checkers bg?
- return (
-
-
-
- );
- }
-
- // Default icon
- let icon = icons['Document'];
-
- if (isDir) {
- icon = icons['Folder'];
- } else if (
- kind &&
- extension &&
- icons[`${kind}_${extension.toLowerCase()}` as keyof typeof icons]
- ) {
- // e.g. Document_pdf
- icon = icons[`${kind}_${extension.toLowerCase()}` as keyof typeof icons];
- } else if (kind !== 'Unknown' && kind && icons[kind]) {
- icon = icons[kind];
- }
-
- // TODO: Handle video thumbnails (do we have ffmpeg on mobile?)
-
- // // 10 percent of the size
- // const videoBarsHeight = Math.floor(size / 10);
-
- // // calculate 16:9 ratio for height from size
- // const videoHeight = Math.floor((size * 9) / 16) + videoBarsHeight * 2;
+ switch (thumbType) {
+ // case ThumbType.Original:
+ // if (locationId) {
+ // setSrc(
+ // platform.getFileUrl(
+ // library.uuid,
+ // locationId,
+ // filePath?.id || props.data.item.id,
+ // // Workaround Linux webview not supporting playing video and audio through custom protocol urls
+ // kind == 'Video' || kind == 'Audio'
+ // )
+ // );
+ // } else {
+ // setThumbType(ThumbType.Thumbnail);
+ // }
+ // break;
+ case ThumbType.Thumbnail:
+ if (casId && thumbnailKey) {
+ setSrc(getThumbnailUrlByThumbKey(thumbnailKey));
+ } else {
+ setThumbType(ThumbType.Icon);
+ }
+ break;
+ case ThumbType.Location:
+ setSrc(getIcon('Folder', isDarkTheme(), extension, true));
+ break;
+ default:
+ if (isDir !== null) setSrc(getIcon(kind, isDarkTheme(), extension, isDir));
+ break;
+ }
+ }, [filePath?.id, itemData, props.data.item.id, thumbType]);
return (
-
+ {(() => {
+ if (src == null) return null;
+ let source = null;
+ // getIcon returns number for some magic reason
+ if (typeof src === 'number') {
+ source = src;
+ } else {
+ source = { uri: src };
+ }
+ return ;
+ })()}
);
}
diff --git a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx
index 759d319d2..fe1cc95d8 100644
--- a/apps/mobile/src/screens/settings/client/GeneralSettings.tsx
+++ b/apps/mobile/src/screens/settings/client/GeneralSettings.tsx
@@ -1,5 +1,5 @@
import { Text, View } from 'react-native';
-import { useBridgeQuery } from '@sd/client';
+import { useBridgeQuery, useDebugState } from '@sd/client';
import { Input } from '~/components/form/Input';
import Card from '~/components/layout/Card';
import { Divider } from '~/components/primitive/Divider';
@@ -10,6 +10,8 @@ import { SettingsStackScreenProps } from '~/navigation/SettingsNavigator';
const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'GeneralSettings'>) => {
const { data: node } = useBridgeQuery(['nodeState']);
+ const debugState = useDebugState();
+
if (!node) return null;
return (
@@ -37,6 +39,18 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General
Node Port
+ {/* TODO: Move this to Debug screen */}
+ {debugState.enabled && (
+
+ {/* Card Header */}
+ Debug
+ {/* Divider */}
+
+ Data Folder
+ {/* Useful for simulator, not so for real devices. */}
+
+
+ )}
);
};
diff --git a/apps/mobile/src/stores/explorerStore.ts b/apps/mobile/src/stores/explorerStore.ts
index 6e26ddfc1..e2ac60f63 100644
--- a/apps/mobile/src/stores/explorerStore.ts
+++ b/apps/mobile/src/stores/explorerStore.ts
@@ -17,7 +17,7 @@ const state = {
newThumbnails: proxySet() as Set
};
-function flattenThumbnailKey(thumbKey: string[]) {
+export function flattenThumbnailKey(thumbKey: string[]) {
return thumbKey.join('/');
}
diff --git a/packages/client/src/hooks/useThemeStore.ts b/packages/client/src/hooks/useThemeStore.ts
index 07ff71311..dc8fbabd4 100644
--- a/packages/client/src/hooks/useThemeStore.ts
+++ b/packages/client/src/hooks/useThemeStore.ts
@@ -16,3 +16,7 @@ export function useThemeStore() {
export function getThemeStore() {
return themeStore;
}
+
+export function isDarkTheme() {
+ return themeStore.theme === 'dark';
+}