mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-18 13:26:00 -04:00
[MOB-37, MOB-38, MOB-39] Preview for PDF, Text and Media files (#2098)
* version & microphonePermission text & eslint * remove polyfill as hermes supports intl now * why do we have solid on mobile? * cleanup * add solid back =_= * pnpm lock * we hate relative paths here * android config * open file logic * visual tweaks --------- Co-authored-by: ameer2468 <33054370+ameer2468@users.noreply.github.com>
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
"name": "Spacedrive",
|
||||
"slug": "spacedrive",
|
||||
"owner": "spacedrive",
|
||||
"version": "0.0.1",
|
||||
"version": "0.1.0",
|
||||
"orientation": "portrait",
|
||||
"jsEngine": "hermes",
|
||||
"scheme": "spacedrive",
|
||||
@@ -58,7 +58,14 @@
|
||||
}
|
||||
}
|
||||
],
|
||||
["./withRiveAssets.js"]
|
||||
[
|
||||
"expo-av",
|
||||
{
|
||||
"microphonePermission": "Allow Spacedrive to access your microphone."
|
||||
}
|
||||
],
|
||||
["./scripts/withRiveAssets.js"],
|
||||
["./scripts/withAndroidIntent.js"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ apply plugin: 'maven-publish'
|
||||
|
||||
|
||||
group = 'com.spacedrive.core'
|
||||
version = '0.0.1'
|
||||
version = '0.1.0'
|
||||
|
||||
buildscript {
|
||||
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
||||
@@ -72,7 +72,7 @@ android {
|
||||
minSdkVersion safeExtGet("minSdkVersion", 28)
|
||||
targetSdkVersion safeExtGet("targetSdkVersion", 34)
|
||||
versionCode 1
|
||||
versionName "0.2.0"
|
||||
versionName "0.1.0"
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
|
||||
@@ -1,83 +1,84 @@
|
||||
{
|
||||
"name": "@sd/mobile",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "GPL-3.0-only",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "expo start --dev-client",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"prebuild": "expo prebuild",
|
||||
"xcode": "open ios/Spacedrive.xcworkspace",
|
||||
"android-studio": "open -a '/Applications/Android Studio.app' ./android",
|
||||
"lint": "eslint src --cache",
|
||||
"test": "cd ../.. && ./apps/mobile/scripts/run-maestro-tests ios",
|
||||
"export": "expo export",
|
||||
"typecheck": "tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
"@gorhom/bottom-sheet": "^4.4.7",
|
||||
"@hookform/resolvers": "^3.1.0",
|
||||
"@oscartbeaumont-sd/rspc-client": "=0.0.0-main-dc31e5b2",
|
||||
"@oscartbeaumont-sd/rspc-react": "=0.0.0-main-dc31e5b2",
|
||||
"@react-native-async-storage/async-storage": "~1.21.0",
|
||||
"@react-native-masked-view/masked-view": "^0.3.0",
|
||||
"@react-navigation/bottom-tabs": "^6.5.8",
|
||||
"@react-navigation/drawer": "^6.6.3",
|
||||
"@react-navigation/native": "^6.1.7",
|
||||
"@react-navigation/stack": "^6.3.17",
|
||||
"@sd/assets": "workspace:*",
|
||||
"@sd/client": "workspace:*",
|
||||
"@shopify/flash-list": "1.6.3",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"babel-preset-solid": "^1.8.9",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"event-target-polyfill": "^0.0.3",
|
||||
"expo": "~50.0.6",
|
||||
"expo-av": "^13.10.5",
|
||||
"expo-blur": "^12.9.1",
|
||||
"expo-build-properties": "~0.11.1",
|
||||
"expo-linking": "~6.2.2",
|
||||
"expo-media-library": "~15.9.1",
|
||||
"expo-splash-screen": "~0.26.4",
|
||||
"expo-status-bar": "~1.11.1",
|
||||
"intl": "^1.2.5",
|
||||
"lottie-react-native": "6.5.1",
|
||||
"metro-react-native-babel-transformer": "^0.77.0",
|
||||
"moti": "^0.26.0",
|
||||
"phosphor-react-native": "^2.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-hook-form": "^7.47.0",
|
||||
"react-native": "0.73.4",
|
||||
"react-native-circular-progress": "^1.3.9",
|
||||
"react-native-document-picker": "^9.0.1",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "~2.14.1",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-popup-menu": "^0.16.1",
|
||||
"react-native-reanimated": "~3.6.2",
|
||||
"react-native-safe-area-context": "4.8.2",
|
||||
"react-native-screens": "~3.29.0",
|
||||
"react-native-svg": "14.1.0",
|
||||
"react-native-wheel-color-picker": "^1.2.0",
|
||||
"rive-react-native": "^6.2.3",
|
||||
"solid-js": "^1.8.8",
|
||||
"twrnc": "^3.6.4",
|
||||
"use-count-up": "^3.0.1",
|
||||
"use-debounce": "^9.0.4",
|
||||
"valtio": "^1.11.2",
|
||||
"zod": "~3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@rnx-kit/metro-config": "^1.3.12",
|
||||
"@sd/config": "workspace:*",
|
||||
"@types/react": "^18.2.52",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"eslint-plugin-react-native": "^4.1.0",
|
||||
"react-native-svg-transformer": "^1.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
"name": "@sd/mobile",
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"license": "GPL-3.0-only",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "expo start --dev-client",
|
||||
"android": "expo run:android",
|
||||
"ios": "expo run:ios",
|
||||
"prebuild": "expo prebuild",
|
||||
"xcode": "open ios/Spacedrive.xcworkspace",
|
||||
"android-studio": "open -a '/Applications/Android Studio.app' ./android",
|
||||
"lint": "eslint src --cache",
|
||||
"test": "cd ../.. && ./apps/mobile/scripts/run-maestro-tests ios",
|
||||
"export": "expo export",
|
||||
"typecheck": "tsc -b",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@gorhom/bottom-sheet": "^4.4.7",
|
||||
"@hookform/resolvers": "^3.1.0",
|
||||
"@oscartbeaumont-sd/rspc-client": "=0.0.0-main-dc31e5b2",
|
||||
"@oscartbeaumont-sd/rspc-react": "=0.0.0-main-dc31e5b2",
|
||||
"@react-native-async-storage/async-storage": "~1.21.0",
|
||||
"@react-native-masked-view/masked-view": "^0.3.0",
|
||||
"@react-navigation/bottom-tabs": "^6.5.8",
|
||||
"@react-navigation/drawer": "^6.6.3",
|
||||
"@react-navigation/native": "^6.1.7",
|
||||
"@react-navigation/stack": "^6.3.17",
|
||||
"@sd/assets": "workspace:*",
|
||||
"@sd/client": "workspace:*",
|
||||
"@shopify/flash-list": "1.6.3",
|
||||
"@tanstack/react-query": "^4.36.1",
|
||||
"babel-preset-solid": "^1.8.9",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"dayjs": "^1.11.10",
|
||||
"event-target-polyfill": "^0.0.3",
|
||||
"expo": "~50.0.6",
|
||||
"expo-av": "^13.10.5",
|
||||
"expo-blur": "^12.9.1",
|
||||
"expo-build-properties": "~0.11.1",
|
||||
"expo-linking": "~6.2.2",
|
||||
"expo-media-library": "~15.9.1",
|
||||
"expo-splash-screen": "~0.26.4",
|
||||
"expo-status-bar": "~1.11.1",
|
||||
"lottie-react-native": "6.5.1",
|
||||
"metro-react-native-babel-transformer": "^0.77.0",
|
||||
"moti": "^0.26.0",
|
||||
"phosphor-react-native": "^2.0.0",
|
||||
"react": "^18.2.0",
|
||||
"react-hook-form": "^7.47.0",
|
||||
"react-native": "0.73.4",
|
||||
"react-native-circular-progress": "^1.3.9",
|
||||
"react-native-document-picker": "^9.0.1",
|
||||
"react-native-file-viewer": "^2.1.5",
|
||||
"react-native-fs": "^2.20.0",
|
||||
"react-native-gesture-handler": "~2.14.1",
|
||||
"react-native-linear-gradient": "^2.8.3",
|
||||
"react-native-popup-menu": "^0.16.1",
|
||||
"react-native-reanimated": "~3.6.2",
|
||||
"react-native-safe-area-context": "4.8.2",
|
||||
"react-native-screens": "~3.29.0",
|
||||
"react-native-svg": "14.1.0",
|
||||
"react-native-wheel-color-picker": "^1.2.0",
|
||||
"rive-react-native": "^6.2.3",
|
||||
"solid-js": "^1.8.8",
|
||||
"twrnc": "^3.6.4",
|
||||
"use-count-up": "^3.0.1",
|
||||
"use-debounce": "^9.0.4",
|
||||
"valtio": "^1.11.2",
|
||||
"zod": "~3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
"@rnx-kit/metro-config": "^1.3.12",
|
||||
"@sd/config": "workspace:*",
|
||||
"@types/react": "^18.2.52",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"eslint-plugin-react-native": "^4.1.0",
|
||||
"react-native-svg-transformer": "^1.1.0",
|
||||
"typescript": "^5.3.3"
|
||||
}
|
||||
}
|
||||
|
||||
26
apps/mobile/scripts/withAndroidIntent.js
Normal file
26
apps/mobile/scripts/withAndroidIntent.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const { withAndroidManifest } = require('@expo/config-plugins');
|
||||
|
||||
// NOTE: Can be extended if needed (https://forums.expo.dev/t/how-to-edit-android-manifest-was-build/65663/4)
|
||||
function modifyAndroidManifest(androidManifest) {
|
||||
const { manifest } = androidManifest;
|
||||
|
||||
const intent = manifest['queries'][0]['intent'][0];
|
||||
|
||||
if (intent) {
|
||||
// Adds <data android:mimeType="*/*" /> to the intents
|
||||
intent['data'].push({
|
||||
$: {
|
||||
'android:mimeType': '*/*'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return androidManifest;
|
||||
}
|
||||
|
||||
module.exports = function withAndroidIntent(config) {
|
||||
return withAndroidManifest(config, (config) => {
|
||||
config.modResults = modifyAndroidManifest(config.modResults);
|
||||
return config;
|
||||
});
|
||||
};
|
||||
@@ -68,11 +68,7 @@ function AppNavigation() {
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
plausibleEvent({
|
||||
event: {
|
||||
type: 'ping'
|
||||
}
|
||||
});
|
||||
plausibleEvent({ event: { type: 'ping' } });
|
||||
}, 270 * 1000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useActionsModalStore } from '~/stores/modalStore';
|
||||
|
||||
import FileItem from './FileItem';
|
||||
import FileRow from './FileRow';
|
||||
import ScreenContainer from '../layout/ScreenContainer';
|
||||
|
||||
type ExplorerProps = {
|
||||
items?: ExplorerItem[];
|
||||
@@ -44,7 +45,7 @@ const Explorer = ({ items }: ExplorerProps) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={tw`flex-1 bg-mobile-screen`}>
|
||||
<ScreenContainer style={'gap-0 py-0'} scrollview={false}>
|
||||
{/* Header */}
|
||||
<View style={tw`flex flex-row items-center justify-between`}>
|
||||
{/* Sort By */}
|
||||
@@ -99,6 +100,7 @@ const Explorer = ({ items }: ExplorerProps) => {
|
||||
)}
|
||||
</Pressable>
|
||||
)}
|
||||
contentContainerStyle={tw`p-2`}
|
||||
extraData={layoutMode}
|
||||
estimatedItemSize={
|
||||
layoutMode === 'grid'
|
||||
@@ -107,7 +109,7 @@ const Explorer = ({ items }: ExplorerProps) => {
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
</ScreenContainer>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useNavigation } from '@react-navigation/native';
|
||||
import { StackHeaderProps } from '@react-navigation/stack';
|
||||
import { ArrowLeft, DotsThreeOutline, MagnifyingGlass } from 'phosphor-react-native';
|
||||
import { lazy } from 'react';
|
||||
import { Platform, Pressable, Text, View } from 'react-native';
|
||||
import { Pressable, Text, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { tw, twStyle } from '~/lib/tailwind';
|
||||
import { getExplorerStore, useExplorerStore } from '~/stores/explorerStore';
|
||||
|
||||
@@ -44,16 +45,18 @@ export default function Header({
|
||||
const explorerStore = useExplorerStore();
|
||||
const routeParams = route?.route.params as any;
|
||||
|
||||
const headerHeight = useSafeAreaInsets().top;
|
||||
|
||||
return (
|
||||
<View
|
||||
style={twStyle(
|
||||
'relative h-auto w-full border-b border-app-line/50 bg-mobile-header',
|
||||
Platform.OS === 'android' ? 'pt-5' : 'pt-10'
|
||||
{ paddingTop: headerHeight }
|
||||
)}
|
||||
>
|
||||
<View style={tw`mx-auto mt-5 h-auto w-full justify-center px-7 pb-5`}>
|
||||
<View style={tw`mx-auto h-auto w-full justify-center px-7 pb-5`}>
|
||||
<View style={tw`w-full flex-row items-center justify-between`}>
|
||||
<View style={tw`flex-row items-center gap-5`}>
|
||||
<View style={tw`flex-row items-center gap-3`}>
|
||||
{navBack && (
|
||||
<Pressable
|
||||
onPress={() => {
|
||||
@@ -67,7 +70,7 @@ export default function Header({
|
||||
<HeaderIconKind headerKind={headerKind} routeParams={routeParams} />
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={tw`max-w-[190px] text-[22px] font-bold text-white`}
|
||||
style={tw`max-w-[200px] text-xl font-bold text-white`}
|
||||
>
|
||||
{title || (routeTitle && route?.options.title)}
|
||||
</Text>
|
||||
@@ -128,11 +131,11 @@ interface HeaderIconKindProps {
|
||||
const HeaderIconKind = ({ headerKind, routeParams }: HeaderIconKindProps) => {
|
||||
switch (headerKind) {
|
||||
case 'location':
|
||||
return <Icon size={32} name="Folder" />;
|
||||
return <Icon size={30} name="Folder" />;
|
||||
case 'tag':
|
||||
return (
|
||||
<View
|
||||
style={twStyle('h-6 w-6 rounded-full', {
|
||||
style={twStyle('h-[30px] w-[30px] rounded-full', {
|
||||
backgroundColor: routeParams.color
|
||||
})}
|
||||
/>
|
||||
|
||||
@@ -12,7 +12,14 @@ import {
|
||||
} from 'phosphor-react-native';
|
||||
import { PropsWithChildren, useRef } from 'react';
|
||||
import { Pressable, Text, View, ViewStyle } from 'react-native';
|
||||
import { byteSize, getItemFilePath, getItemObject } from '@sd/client';
|
||||
import FileViewer from 'react-native-file-viewer';
|
||||
import {
|
||||
byteSize,
|
||||
getIndexedItemFilePath,
|
||||
getItemObject,
|
||||
useLibraryMutation,
|
||||
useLibraryQuery
|
||||
} from '@sd/client';
|
||||
import FileThumb from '~/components/explorer/FileThumb';
|
||||
import FavoriteButton from '~/components/explorer/sections/FavoriteButton';
|
||||
import InfoTagPills from '~/components/explorer/sections/InfoTagPills';
|
||||
@@ -32,7 +39,7 @@ const ActionsContainer = ({ children, style }: ActionsContainerProps) => (
|
||||
|
||||
type ActionsItemProps = {
|
||||
title: string;
|
||||
icon: Icon;
|
||||
icon?: Icon;
|
||||
onPress?: () => void;
|
||||
isDanger?: boolean;
|
||||
};
|
||||
@@ -49,7 +56,7 @@ const ActionsItem = ({ icon, onPress, title, isDanger = false }: ActionsItemProp
|
||||
>
|
||||
{title}
|
||||
</Text>
|
||||
<Icon color={isDanger ? 'red' : 'white'} size={22} />
|
||||
{Icon && <Icon color={isDanger ? 'red' : 'white'} size={22} />}
|
||||
</Pressable>
|
||||
);
|
||||
};
|
||||
@@ -62,7 +69,31 @@ export const ActionsModal = () => {
|
||||
const { modalRef, data } = useActionsModalStore();
|
||||
|
||||
const objectData = data && getItemObject(data);
|
||||
const filePath = data && getItemFilePath(data);
|
||||
const filePath = data && getIndexedItemFilePath(data);
|
||||
|
||||
// Open
|
||||
|
||||
const updateAccessTime = useLibraryMutation('files.updateAccessTime');
|
||||
const queriedFullPath = useLibraryQuery(['files.getPath', filePath?.id ?? -1], {
|
||||
enabled: filePath != null
|
||||
});
|
||||
|
||||
async function handleOpen() {
|
||||
const absolutePath = queriedFullPath.data;
|
||||
if (!absolutePath) return;
|
||||
try {
|
||||
await FileViewer.open(absolutePath, {
|
||||
// Android only
|
||||
showAppsSuggestions: false, // If there is not an installed app that can open the file, open the Play Store with suggested apps
|
||||
showOpenWithDialog: true // if there is more than one app that can open the file, show an Open With dialogue box
|
||||
});
|
||||
filePath &&
|
||||
filePath.object_id &&
|
||||
updateAccessTime.mutateAsync([filePath.object_id]).catch(console.error);
|
||||
} catch (error) {
|
||||
// TODO: Handle Error & toast message
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -99,6 +130,8 @@ export const ActionsModal = () => {
|
||||
<View style={tw`my-3`} />
|
||||
{/* Actions */}
|
||||
<ActionsContainer>
|
||||
<ActionsItem title="Open" onPress={handleOpen} />
|
||||
<ActionDivider />
|
||||
<ActionsItem
|
||||
icon={Info}
|
||||
title="Show Info"
|
||||
|
||||
@@ -7,26 +7,19 @@ import OverviewSection from './OverviewSection';
|
||||
|
||||
const Cloud = () => {
|
||||
return (
|
||||
<View>
|
||||
<OverviewSection title="Cloud Drives" count={0}>
|
||||
<View style={tw`px-7`}>
|
||||
<NewCard
|
||||
icons={[
|
||||
'DriveAmazonS3',
|
||||
'DriveDropbox',
|
||||
'DriveGoogleDrive',
|
||||
'DriveOneDrive'
|
||||
]}
|
||||
text="Connect your cloud accounts to Spacedrive."
|
||||
button={() => (
|
||||
<Button variant="transparent">
|
||||
<Text style={tw`font-bold text-ink-dull`}>Coming soon</Text>
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</OverviewSection>
|
||||
</View>
|
||||
<OverviewSection title="Cloud Drives" count={0}>
|
||||
<View style={tw`px-7`}>
|
||||
<NewCard
|
||||
icons={['DriveAmazonS3', 'DriveDropbox', 'DriveGoogleDrive', 'DriveOneDrive']}
|
||||
text="Connect your cloud accounts to Spacedrive."
|
||||
button={() => (
|
||||
<Button variant="transparent">
|
||||
<Text style={tw`font-bold text-ink-dull`}>Coming soon</Text>
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</OverviewSection>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ const Locations = ({ locations }: Props) => {
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
return (
|
||||
<View>
|
||||
<>
|
||||
<OverviewSection title="Locations" count={locations?.length}>
|
||||
<View style={tw`flex-row items-center`}>
|
||||
<Fade height={'100%'} width={30} color="mobile-screen">
|
||||
@@ -80,7 +80,7 @@ const Locations = ({ locations }: Props) => {
|
||||
</View>
|
||||
</OverviewSection>
|
||||
<ImportModal ref={modalRef} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -94,20 +94,6 @@ window.screen = {
|
||||
height
|
||||
};
|
||||
|
||||
/*
|
||||
https://github.com/facebook/hermes/issues/23
|
||||
|
||||
We are using "Hermes" on Android & IOS, which for the current version (0.11),
|
||||
IOS does not support the Intl fully so we need polyfill it.
|
||||
|
||||
NOTE: We can be picky about what we "polyfill" to optimize but for now this works.
|
||||
*/
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
require('intl'); // import intl object
|
||||
require('intl/locale-data/jsonp/en');
|
||||
}
|
||||
|
||||
// This is insane. We load all data from `AsyncStorage` into the `_localStorage` global and then once complete we import the app.
|
||||
// This way the polyfilled `localStorage` implementation has its data populated before the global stores within `@sd/client` are initialized (as they are initialized on import).
|
||||
const App = lazy(async () => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useMemo } from 'react';
|
||||
import { useEffect, useMemo } from 'react';
|
||||
import { useCache, useLibraryQuery, useNodes } from '@sd/client';
|
||||
import Explorer from '~/components/explorer/Explorer';
|
||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||
@@ -11,21 +11,23 @@ export default function LocationScreen({ navigation, route }: BrowseStackScreenP
|
||||
useNodes(location.data?.nodes);
|
||||
const locationData = useCache(location.data?.item);
|
||||
|
||||
const { data } = useLibraryQuery([
|
||||
const paths = useLibraryQuery([
|
||||
'search.paths',
|
||||
{
|
||||
filters: [
|
||||
{
|
||||
filePath: {
|
||||
locations: { in: [id] },
|
||||
path: { path: path ?? '', location_id: id, include_descendants: false }
|
||||
locations: { in: [id] }
|
||||
// path: {location_id: id, path: path ?? '', include_descendants: true} // FIXME: This is the correct query, but it doesn't work and then provides a deserialization error.
|
||||
}
|
||||
}
|
||||
],
|
||||
take: 100
|
||||
}
|
||||
]);
|
||||
const pathsItemsReferences = useMemo(() => data?.items ?? [], [data]);
|
||||
|
||||
const pathsItemsReferences = useMemo(() => paths.data?.items ?? [], [paths.data]);
|
||||
useNodes(paths.data?.nodes);
|
||||
const pathsItems = useCache(pathsItemsReferences);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -2,10 +2,13 @@ import { proxy, useSnapshot } from 'valtio';
|
||||
import { proxySet } from 'valtio/utils';
|
||||
import { resetStore } from '@sd/client';
|
||||
|
||||
// TODO: Add "media"
|
||||
export type ExplorerLayoutMode = 'list' | 'grid' | 'media';
|
||||
|
||||
export type ExplorerKind = 'Location' | 'Tag' | 'Space';
|
||||
export enum ExplorerKind {
|
||||
Location,
|
||||
Tag,
|
||||
Space
|
||||
}
|
||||
|
||||
const state = {
|
||||
locationId: null as number | null,
|
||||
|
||||
@@ -251,9 +251,7 @@ function Options({
|
||||
<Tooltip label={t('pause')}>
|
||||
<Button
|
||||
className="cursor-pointer"
|
||||
onClick={() => {
|
||||
pauseJob.mutate(group.id);
|
||||
}}
|
||||
onClick={() => pauseJob.mutate(group.id)}
|
||||
size="icon"
|
||||
variant="outline"
|
||||
>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { byteSize } from '.';
|
||||
import { getItemFilePath, getItemLocation, getItemObject, type ObjectKindKey } from '..';
|
||||
import type { ExplorerItem } from '../core';
|
||||
import { ObjectKind } from './objectKind';
|
||||
import { getItemFilePath, getItemLocation, getItemObject } from '../utils';
|
||||
import { byteSize } from './byte-size';
|
||||
import { ObjectKind, ObjectKindKey } from './objectKind';
|
||||
|
||||
// ItemData is a single data structure understood by the Explorer, we map all ExplorerItems to this structure in this file
|
||||
// we use `null` instead of `?` optional values intentionally
|
||||
|
||||
BIN
pnpm-lock.yaml
generated
BIN
pnpm-lock.yaml
generated
Binary file not shown.
Reference in New Issue
Block a user