51 lines
1.9 KiB
TypeScript
51 lines
1.9 KiB
TypeScript
import type { ReactElement } from 'react';
|
|
import { Linking, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
import type { MediaRef } from '@altricade/core';
|
|
import { Icon } from '@/components';
|
|
import { useTheme } from '@/theme';
|
|
import { spacing, radius, fontSize } from '@/theme';
|
|
import { useMediaUrl, formatBytes } from '../media';
|
|
|
|
interface Props {
|
|
conversationId: string;
|
|
messageId: string;
|
|
media: MediaRef;
|
|
outgoing: boolean;
|
|
}
|
|
|
|
// Generic file attachment — tapping opens the presigned url in the OS handler.
|
|
export const FileBubble = ({ conversationId, messageId, media, outgoing }: Props): ReactElement => {
|
|
const { colors } = useTheme();
|
|
const url = useMediaUrl(conversationId, messageId, true);
|
|
const nameTone = outgoing ? colors.onAccent : colors.text;
|
|
const subTone = outgoing ? colors.onAccentMuted : colors.textFaint;
|
|
return (
|
|
<Pressable
|
|
disabled={url === null}
|
|
onPress={() => {
|
|
if (url !== null) {
|
|
void Linking.openURL(url);
|
|
}
|
|
}}
|
|
style={styles.row}
|
|
>
|
|
<View style={[styles.icon, { backgroundColor: outgoing ? colors.onAccentMuted : colors.accentSoft }]}>
|
|
<Icon name="file" size={20} color={outgoing ? colors.onAccent : colors.accent} />
|
|
</View>
|
|
<View style={styles.meta}>
|
|
<Text style={[styles.name, { color: nameTone }]} numberOfLines={1}>
|
|
{media.name}
|
|
</Text>
|
|
<Text style={[styles.size, { color: subTone }]}>{formatBytes(media.size)}</Text>
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
row: { flexDirection: 'row', alignItems: 'center', gap: spacing.md, minWidth: 180 },
|
|
icon: { width: 42, height: 42, borderRadius: radius.md, alignItems: 'center', justifyContent: 'center' },
|
|
meta: { flex: 1, gap: 2 },
|
|
name: { fontSize: fontSize.base, fontWeight: '600' },
|
|
size: { fontSize: fontSize.xs },
|
|
});
|