Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
204 changes: 102 additions & 102 deletions ios/Internxt.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
Expand Down
2 changes: 1 addition & 1 deletion ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ target 'Internxt' do
end

target 'InternxtShareExtension' do
exclude = ["expo-updates", "expo-splash-screen", "expo-dev-client", "react-native-reanimated", "react-native-screens", "react-native-safe-area-context", "react-native-gesture-handler", "react-native-video", "react-native-webview", "react-native-fast-image", "react-native-svg", "@shopify/flash-list", "react-native-pdf", "react-native-pdf-thumbnail", "react-native-blob-util", "react-native-create-thumbnail", "jail-monkey"]
exclude = ["expo-updates", "expo-splash-screen", "expo-dev-client", "react-native-reanimated", "react-native-screens", "react-native-safe-area-context", "react-native-gesture-handler", "react-native-video", "react-native-webview", "react-native-fast-image", "react-native-svg", "@shopify/flash-list", "react-native-pdf", "react-native-pdf-thumbnail", "react-native-create-thumbnail", "jail-monkey"]
use_expo_modules!(exclude: exclude)

if ENV['EXPO_USE_COMMUNITY_AUTOLINKING'] == '1'
Expand Down
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2969,6 +2969,6 @@ SPEC CHECKSUMS:
SDWebImageWebPCoder: 908b83b6adda48effe7667cd2b7f78c897e5111d
Yoga: 5934998fbeaef7845dbf698f698518695ab4cd1a

PODFILE CHECKSUM: 5b24f4b19fb116989bb2be5cc815fb62164b2560
PODFILE CHECKSUM: c616d1ada5d84f015b84b48b4ee50b266ab8ecc6

COCOAPODS: 1.16.2
45 changes: 24 additions & 21 deletions src/components/DriveItemSkinSkeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,33 @@
import { DriveListViewMode } from '@internxt-mobile/types/drive/ui';
import React, { useState } from 'react';
import React, { useEffect, useRef } from 'react';
import { Animated, Easing, View } from 'react-native';
import { useTailwind } from 'tailwind-rn';

const DriveItemSkinSkeleton: React.FC<{ viewMode?: DriveListViewMode }> = ({ viewMode }) => {
const DriveItemSkinSkeleton: React.FC<{ viewMode?: 'grid' | 'list' }> = ({ viewMode }) => {
const tailwind = useTailwind();
const [fadeAnim] = useState(new Animated.Value(1));
const fadeAnim = useRef(new Animated.Value(1)).current;

Animated.loop(
Animated.sequence([
Animated.timing(fadeAnim, {
toValue: 0.4,
duration: 1500,
easing: Easing.linear,
useNativeDriver: true,
}),
Animated.timing(fadeAnim, {
toValue: 1,
duration: 800,
easing: Easing.linear,
useNativeDriver: true,
}),
]),
).start();
useEffect(() => {
const anim = Animated.loop(
Animated.sequence([
Animated.timing(fadeAnim, {
toValue: 0.4,
duration: 1500,
easing: Easing.linear,
useNativeDriver: true,
}),
Animated.timing(fadeAnim, {
toValue: 1,
duration: 800,
easing: Easing.linear,
useNativeDriver: true,
}),
]),
);
anim.start();
return () => anim.stop();
}, []);

if (viewMode === DriveListViewMode.Grid) {
if (viewMode === 'grid') {
const renderGridItem = () => {
return (
<View style={[tailwind('items-center flex-col justify-center pt-6 mb-6 w-1/3')]}>
Expand Down
7 changes: 1 addition & 6 deletions src/shareExtension/ShareExtensionView.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,7 @@ const ShareExtensionView = (props: ShareExtensionProps) => {
}

return (
<DriveScreen
sharedFiles={sharedFiles}
rootFolderUuid={props.rootFolderId}
onClose={close}
onSave={handleSave}
/>
<DriveScreen sharedFiles={sharedFiles} rootFolderUuid={props.rootFolderId} onClose={close} onSave={handleSave} />
);
};

Expand Down
217 changes: 217 additions & 0 deletions src/shareExtension/components/BottomFilePanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
import { CaretLeftIcon, CaretRightIcon } from 'phosphor-react-native';
import { useCallback, useMemo } from 'react';
import {
Animated,
Image,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
View,
useWindowDimensions,
} from 'react-native';
import { useTailwind } from 'tailwind-rn';
import StackedFilesIconSvg from '../../../assets/icons/stacked-files.svg';
import strings from '../../../assets/lang/strings';
import { getFileTypeIcon } from '../../helpers/filetypes';
import { useBottomPanelAnimation } from '../hooks/useBottomPanelAnimation';
import { colors, fontStyles } from '../theme';
import { SharedFile } from '../types';
import { formatBytes } from '../utils';
import { TextButton } from './TextButton';

interface BottomFilePanelProps {
sharedFiles: SharedFile[];
editingName: string;
isRenaming: boolean;
onStartRename: () => void;
onChangeName: (name: string) => void;
onEndRename: () => void;
}

const getExtension = (file: SharedFile): string => {
if (file.mimeType) {
const parts = file.mimeType.split('/');
return parts[1]?.toUpperCase() ?? '';
}
if (file.fileName) {
const parts = file.fileName.split('.');
return parts.length > 1 ? (parts[parts.length - 1]?.toUpperCase() ?? '') : '';
}
return '';
};

const getFormats = (files: SharedFile[]): string => {
const exts = new Set(files.map(getExtension).filter(Boolean));
if (exts.size === 0) return '';
if (exts.size === 1) return [...exts][0] ?? '';
return strings.screens.ShareExtension.multipleFormats;
};

const TAB_WIDTH = 44;
const PANEL_MARGIN = 16;
const HANDLE_ICON_SIZE = 16;

const StackedFilesIcon = () => <StackedFilesIconSvg width={48} height={48} style={{ marginRight: 12 }} />;

export const BottomFilePanel = ({
sharedFiles,
editingName,
isRenaming,
onStartRename,
onChangeName,
onEndRename,
}: BottomFilePanelProps) => {
const tailwind = useTailwind();
const { width: screenWidth } = useWindowDimensions();
const { isCollapsed, keyboardBottom, slideAnimation, toggle } = useBottomPanelAnimation(isRenaming, screenWidth);

const formats = useMemo(() => getFormats(sharedFiles), [sharedFiles]);
const totalSize = useMemo(() => {
const sum = sharedFiles.reduce((acc, file) => (file.size != null ? acc + file.size : acc), 0);

Check warning on line 71 in src/shareExtension/components/BottomFilePanel.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-mobile&issues=AZzDZGTayXmjOTWOlADp&open=AZzDZGTayXmjOTWOlADp&pullRequest=383
const hasAnySize = sharedFiles.some((file) => file.size != null);
return hasAnySize ? sum : null;
}, [sharedFiles]);

const containerStyle = useMemo(() => [tailwind('flex-row items-center'), panelStyles.container], [tailwind]);

const file = sharedFiles[0];
const originalFileName = file?.fileName ?? '';
const dotIndex = originalFileName.lastIndexOf('.');
const fileExt = dotIndex > 0 ? originalFileName.slice(dotIndex) : '';
const nameWithoutExt =
fileExt && editingName.endsWith(fileExt) ? editingName.slice(0, editingName.length - fileExt.length) : editingName;

const handleRenameChange = useCallback((name: string) => onChangeName(name + fileExt), [fileExt, onChangeName]);
const handleEndRename = useCallback(() => {
if (!nameWithoutExt.trim()) {
onChangeName(originalFileName || strings.screens.ShareExtension.fileNameFallback);
}
onEndRename();
}, [nameWithoutExt, onChangeName, onEndRename, originalFileName]);

if (sharedFiles.length === 0) return null;

const collapseButton = (
<TouchableOpacity
onPress={toggle}
style={[tailwind('items-center justify-center'), panelStyles.collapseButton]}
hitSlop={4}
>
{isCollapsed ? (
<CaretLeftIcon size={HANDLE_ICON_SIZE} color={colors.gray40} />
) : (
<CaretRightIcon size={HANDLE_ICON_SIZE} color={colors.gray40} />
)}
</TouchableOpacity>
);

const animatedStyle = { bottom: keyboardBottom, transform: [{ translateX: slideAnimation }] };

if (sharedFiles.length > 1) {
return (
<Animated.View style={[...containerStyle, animatedStyle]}>
{collapseButton}
<View style={panelStyles.divider} />
<StackedFilesIcon />
<View style={tailwind('flex-1')}>
<Text style={[tailwind('text-sm text-gray-100'), fontStyles.medium]}>
{strings.formatString(strings.screens.ShareExtension.itemsSelected, sharedFiles.length)}
</Text>
{totalSize != null || formats ? (
<Text style={[tailwind('text-xs text-gray-40 mt-0.5'), fontStyles.regular]}>
{[totalSize != null ? formatBytes(totalSize) : null, formats || null].filter(Boolean).join(' · ')}

Check warning on line 123 in src/shareExtension/components/BottomFilePanel.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-mobile&issues=AZzDZGTayXmjOTWOlADq&open=AZzDZGTayXmjOTWOlADq&pullRequest=383
</Text>
) : null}
</View>
</Animated.View>
);
}

if (!file) return null;
const ext = getExtension(file);
const IconComponent = getFileTypeIcon(ext.toLowerCase());
const displayName = editingName || file.fileName || strings.screens.ShareExtension.fileNameFallback;
const isImage = file.mimeType?.startsWith('image/') ?? false;

return (
<Animated.View style={[...containerStyle, animatedStyle]}>
{collapseButton}
<View style={panelStyles.divider} />
<View style={tailwind('items-center justify-center mr-3 w-10 h-10')}>
{isImage ? (
<Image source={{ uri: file.uri }} style={panelStyles.fileImage} resizeMode="cover" />
) : (
<IconComponent width={36} height={36} />
)}
</View>
<View style={tailwind('flex-1')}>
{isRenaming ? (
<TextInput
style={[tailwind('text-sm text-gray-100 p-0'), fontStyles.medium, panelStyles.renameInput]}
value={nameWithoutExt}
onChangeText={handleRenameChange}
onBlur={handleEndRename}
autoFocus
selectTextOnFocus
returnKeyType="done"
onSubmitEditing={handleEndRename}
/>
) : (
<Text
style={[tailwind('text-sm text-gray-100'), fontStyles.medium, panelStyles.fileNameText]}
numberOfLines={1}
>
{displayName}
</Text>
)}
<Text style={[tailwind('text-xs text-gray-40 mt-0.5'), fontStyles.regular]}>
{file.size != null ? `${formatBytes(file.size)} · ${ext}` : ext}

Check warning on line 169 in src/shareExtension/components/BottomFilePanel.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected negated condition.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-mobile&issues=AZzDZGTayXmjOTWOlADr&open=AZzDZGTayXmjOTWOlADr&pullRequest=383
</Text>
</View>
{!isRenaming && <TextButton title={strings.screens.ShareExtension.rename} onPress={onStartRename} />}
</Animated.View>
);
};

const panelStyles = StyleSheet.create({
container: {
position: 'absolute',
marginHorizontal: PANEL_MARGIN,
paddingHorizontal: PANEL_MARGIN,
paddingVertical: 12,
minHeight: 64,
borderRadius: 20,
borderWidth: 1,
borderColor: colors.gray10,
backgroundColor: colors.surface,
shadowColor: '#000',
shadowOffset: { width: 0, height: 32 },
shadowOpacity: 0.04,
shadowRadius: 40,
elevation: 8,
},
collapseButton: {
width: TAB_WIDTH,
alignSelf: 'stretch',
},
divider: {
width: 1,
alignSelf: 'stretch',
backgroundColor: colors.gray10,
marginRight: 12,
},
fileImage: {
width: 36,
height: 36,
borderRadius: 6,
},
fileNameText: {
paddingRight: 8,
},
renameInput: {
padding: 0,
borderBottomWidth: 1,
borderBottomColor: colors.primary,
},
});
11 changes: 5 additions & 6 deletions src/shareExtension/components/DriveScreen/DriveList.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { DriveListViewMode } from '@internxt-mobile/types/drive/ui';
import { useCallback } from 'react';
import { FlatList, Keyboard, Text, View } from 'react-native';
import DriveItemSkinSkeleton from 'src/components/DriveItemSkinSkeleton';
import { useTailwind } from 'tailwind-rn';
import strings from '../../../../assets/lang/strings';
import { fontStyles } from '../../theme';
import { ShareFileItem, ShareFolderItem } from '../../types';
import { DriveViewMode, ShareFileItem, ShareFolderItem } from '../../types';
import { FileListItem } from '../FileListItem';

export type DriveListItem = { type: 'folder'; data: ShareFolderItem } | { type: 'file'; data: ShareFileItem };
Expand All @@ -14,7 +13,7 @@

interface DriveListProps {
listData: DriveListItem[];
viewMode: DriveListViewMode;
viewMode: DriveViewMode;
loading: boolean;
loadingMore: boolean;
searchQuery: string;
Expand All @@ -32,7 +31,7 @@
onLoadMore,
}: DriveListProps) => {
const tailwind = useTailwind();
const numColumns = viewMode === DriveListViewMode.Grid ? 3 : 1;
const numColumns = viewMode === 'grid' ? 3 : 1;

const renderItem = useCallback(
({ item }: { item: DriveListItem }) => {
Expand All @@ -47,7 +46,7 @@
return (
<View style={tailwind('flex-1')}>
{Array.from({ length: 10 }).map((_, i) => (
<View style={viewMode === DriveListViewMode.Grid ? undefined : tailwind('h-16')} key={i}>
<View style={viewMode === 'grid' ? undefined : tailwind('h-16')} key={i}>

Check warning on line 49 in src/shareExtension/components/DriveScreen/DriveList.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=internxt_drive-mobile&issues=AZzTjqa6Yb1nM1Cj44Fx&open=AZzTjqa6Yb1nM1Cj44Fx&pullRequest=383
<DriveItemSkinSkeleton viewMode={viewMode} />
</View>
))}
Expand All @@ -62,7 +61,7 @@
keyExtractor={keyExtractor}
numColumns={numColumns}
renderItem={renderItem}
contentContainerStyle={viewMode === DriveListViewMode.Grid ? tailwind('px-2') : undefined}
contentContainerStyle={viewMode === 'grid' ? tailwind('px-2') : undefined}
ListEmptyComponent={
<View style={[tailwind('items-center'), { paddingTop: 48 }]}>
<Text style={[tailwind('text-gray-40'), { fontSize: 16, ...fontStyles.regular }]}>
Expand Down
13 changes: 4 additions & 9 deletions src/shareExtension/components/DriveScreen/SortRow.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { DriveListViewMode } from '@internxt-mobile/types/drive/ui';
import { RowsIcon, SquaresFourIcon } from 'phosphor-react-native';
import { Text, TouchableOpacity, View } from 'react-native';
import { useTailwind } from 'tailwind-rn';
import strings from '../../../../assets/lang/strings';
import { colors, fontStyles } from '../../theme';
import { DriveViewMode } from '../../types';

interface SortRowProps {
viewMode: DriveListViewMode;
viewMode: DriveViewMode;
onToggleViewMode: () => void;
}

Expand All @@ -15,16 +15,11 @@ export const SortRow = ({ viewMode, onToggleViewMode }: SortRowProps) => {

return (
<View style={tailwind('flex-row items-center justify-between px-4 pb-1')}>
<Text
style={[
tailwind('text-xs text-gray-60'),
fontStyles.regular,
]}
>
<Text style={[tailwind('text-xs text-gray-60'), fontStyles.regular]}>
{strings.screens.ShareExtension.sortByName}
</Text>
<TouchableOpacity onPress={onToggleViewMode} hitSlop={8}>
{viewMode === DriveListViewMode.List ? (
{viewMode === 'list' ? (
<SquaresFourIcon size={22} color={colors.gray60} />
) : (
<RowsIcon size={22} color={colors.gray60} />
Expand Down
Loading
Loading