diff --git a/app/views/WorkspaceView/ServerAvatar.tsx b/app/views/WorkspaceView/ServerAvatar.tsx
index 99a6e47f88d..475775d295b 100644
--- a/app/views/WorkspaceView/ServerAvatar.tsx
+++ b/app/views/WorkspaceView/ServerAvatar.tsx
@@ -1,9 +1,11 @@
-import React from 'react';
+import React, { useState } from 'react';
import { StyleSheet, View } from 'react-native';
import { Image } from 'expo-image';
+import SkeletonPlaceholder from 'react-native-skeleton-placeholder';
import { isTablet } from '../../lib/methods/helpers';
import { useTheme } from '../../theme';
+import { CustomIcon } from '../../containers/CustomIcon';
const SIZE = 96;
const MARGIN_TOP = isTablet ? 0 : 64;
@@ -21,6 +23,27 @@ const styles = StyleSheet.create({
width: SIZE,
height: SIZE,
borderRadius: BORDER_RADIUS
+ },
+ imageContainer: {
+ width: SIZE,
+ height: SIZE,
+ position: 'relative'
+ },
+ skeletonOverlay: {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ right: 0,
+ bottom: 0,
+ justifyContent: 'center',
+ alignItems: 'center'
+ },
+ fallbackContainer: {
+ width: SIZE,
+ height: SIZE,
+ borderRadius: BORDER_RADIUS,
+ justifyContent: 'center',
+ alignItems: 'center'
}
});
@@ -29,13 +52,88 @@ interface IServerAvatar {
image: string;
}
-// TODO: missing skeleton
const ServerAvatar = React.memo(({ url, image }: IServerAvatar) => {
- const { colors } = useTheme();
+ const { colors, theme } = useTheme();
+ const isDarkMode = theme === 'dark' || theme === 'black';
+
+ const imageUri = image ? `${url}/${image}` : null;
+
+ // Track loading and error states
+ const [loading, setLoading] = useState(() => !!imageUri);
+ const [error, setError] = useState(false);
+
+ // Reset states when image changes
+ React.useEffect(() => {
+ if (imageUri) {
+ setLoading(true);
+ setError(false);
+ } else {
+ setLoading(false);
+ setError(false);
+ }
+ }, [imageUri]);
+
+ const handleLoadStart = () => {
+ setLoading(true);
+ setError(false);
+ };
+
+ const handleLoad = () => {
+ setLoading(false);
+ setError(false);
+ };
+
+ const handleError = () => {
+ setLoading(false);
+ setError(true);
+ };
+
+ // Show fallback icon on error or when no image is provided
+ if (error || !imageUri) {
+ return (
+
+
+
+
+
+ );
+ }
+ // Show the actual image with an overlaid skeleton while loading
return (
- {image && }
+
+
+ {loading && (
+
+
+
+
+
+ )}
+
);
});