sharable eq

This commit is contained in:
Boof2015
2026-07-07 15:52:12 -04:00
parent d05e45e7d3
commit ed6d587f5f
12 changed files with 1323 additions and 31 deletions
+115
View File
@@ -0,0 +1,115 @@
import { useState } from 'react';
import {
Pressable,
StyleSheet,
View
} from 'react-native';
import { BottomSheetTextInput } from '@gorhom/bottom-sheet';
import { Text } from '@/components/Text';
import {
fonts,
radius,
spacing,
} from '@/theme';
import { createThemedStyles, useColors } from '@/theme/themed';
import { EqSheet } from './EqSheet';
interface EQPresetNameSheetProps {
defaultName: string;
actionLabel: string;
onSubmit: (name: string) => void;
onClose: () => void;
}
export function EQPresetNameSheet({
defaultName,
actionLabel,
onSubmit,
onClose,
}: EQPresetNameSheetProps) {
const styles = useStyles();
const colors = useColors();
const [name, setName] = useState(defaultName);
const trimmed = name.trim();
const submit = () => {
if (!trimmed) return;
onClose();
onSubmit(trimmed);
};
return (
<EqSheet onClose={onClose}>
<Text variant="heading" style={styles.title}>
Name preset
</Text>
<BottomSheetTextInput
value={name}
onChangeText={setName}
placeholder="Preset name"
placeholderTextColor={colors.textTertiary}
style={styles.input}
autoFocus
selectTextOnFocus
maxLength={40}
returnKeyType="done"
onSubmitEditing={submit}
/>
<View style={styles.actions}>
<Pressable style={[styles.btn, styles.cancel]} onPress={onClose}>
<Text variant="label" color={colors.textSecondary}>
Cancel
</Text>
</Pressable>
<Pressable style={[styles.btn, styles.primary, !trimmed && styles.disabled]} disabled={!trimmed} onPress={submit}>
<Text variant="label" color={colors.accentTextStrong}>
{actionLabel}
</Text>
</Pressable>
</View>
</EqSheet>
);
}
const useStyles = createThemedStyles((colors) => ({
title: {
marginTop: spacing.xs,
marginBottom: spacing.md,
},
input: {
color: colors.textPrimary,
fontFamily: fonts.sans.regular,
fontSize: 16,
paddingHorizontal: spacing.md,
paddingVertical: spacing.md,
borderRadius: radius.md,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.glassBorder,
backgroundColor: colors.glassBg,
},
actions: {
flexDirection: 'row',
justifyContent: 'flex-end',
gap: spacing.sm,
marginTop: spacing.lg,
},
btn: {
paddingHorizontal: spacing.xl,
paddingVertical: spacing.md,
borderRadius: radius.pill,
},
cancel: {
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.glassBorder,
},
primary: {
backgroundColor: colors.accentGlow,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.accent,
},
disabled: {
opacity: 0.4,
},
}));
export default EQPresetNameSheet;
+133
View File
@@ -0,0 +1,133 @@
import {
Pressable,
StyleSheet,
View
} from 'react-native';
import { Text } from '@/components/Text';
import {
radius,
spacing,
} from '@/theme';
import { createThemedStyles, useColors } from '@/theme/themed';
import type { EQPreset } from '@/types/audio';
import { EqSheet } from './EqSheet';
import { formatGain } from './format';
interface EQPresetPreviewSheetProps {
preset: EQPreset;
title?: string;
confirmLabel?: string;
onConfirm: () => void;
onClose: () => void;
}
export function EQPresetPreviewSheet({
preset,
title = 'Import preset',
confirmLabel = 'Import and Apply',
onConfirm,
onClose,
}: EQPresetPreviewSheetProps) {
const styles = useStyles();
const colors = useColors();
const enabledBands = preset.bands.filter((band) => band.enabled).length;
const modeLabel = preset.mode === 'graphic' ? 'Graphic' : 'Parametric';
return (
<EqSheet onClose={onClose}>
<Text variant="heading" style={styles.title}>
{title}
</Text>
<View style={styles.preview}>
<Text variant="body" numberOfLines={1} color={colors.textPrimary}>
{preset.name}
</Text>
<View style={styles.metaRow}>
<Text variant="caption" color={colors.textTertiary}>
Mode
</Text>
<Text variant="label" color={colors.textSecondary}>
{modeLabel}
</Text>
</View>
<View style={styles.metaRow}>
<Text variant="caption" color={colors.textTertiary}>
Preamp
</Text>
<Text variant="label" color={colors.textSecondary}>
{formatGain(preset.preamp)} dB
</Text>
</View>
<View style={styles.metaRow}>
<Text variant="caption" color={colors.textTertiary}>
Bands
</Text>
<Text variant="label" color={colors.textSecondary}>
{enabledBands}/{preset.bands.length}
</Text>
</View>
</View>
<View style={styles.actions}>
<Pressable style={[styles.btn, styles.cancel]} onPress={onClose}>
<Text variant="label" color={colors.textSecondary}>
Cancel
</Text>
</Pressable>
<Pressable
style={[styles.btn, styles.primary]}
onPress={() => {
onConfirm();
onClose();
}}
>
<Text variant="label" color={colors.accentTextStrong}>
{confirmLabel}
</Text>
</Pressable>
</View>
</EqSheet>
);
}
const useStyles = createThemedStyles((colors) => ({
title: {
marginTop: spacing.xs,
marginBottom: spacing.md,
},
preview: {
borderRadius: radius.md,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.glassBorder,
backgroundColor: colors.glassBg,
padding: spacing.md,
gap: spacing.sm,
},
metaRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: spacing.md,
},
actions: {
flexDirection: 'row',
justifyContent: 'flex-end',
gap: spacing.sm,
marginTop: spacing.lg,
},
btn: {
paddingHorizontal: spacing.lg,
paddingVertical: spacing.md,
borderRadius: radius.pill,
},
cancel: {
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.glassBorder,
},
primary: {
backgroundColor: colors.accentGlow,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.accent,
},
}));
export default EQPresetPreviewSheet;
+75
View File
@@ -0,0 +1,75 @@
import {
Pressable,
StyleSheet,
View
} from 'react-native';
import QRCode from 'react-native-qrcode-svg';
import { Text } from '@/components/Text';
import {
radius,
spacing,
} from '@/theme';
import { createThemedStyles, useColors } from '@/theme/themed';
import { EqSheet } from './EqSheet';
interface EQPresetQrSheetProps {
presetName: string;
value: string;
onClose: () => void;
}
export function EQPresetQrSheet({ presetName, value, onClose }: EQPresetQrSheetProps) {
const styles = useStyles();
const colors = useColors();
return (
<EqSheet onClose={onClose}>
<Text variant="heading" style={styles.title}>
Preset QR
</Text>
<View style={styles.qrWrap}>
<QRCode value={value} size={220} color="#000000" backgroundColor="#ffffff" quietZone={12} ecl="M" />
</View>
<Text variant="label" numberOfLines={1} color={colors.textSecondary} style={styles.name}>
{presetName}
</Text>
<Pressable style={styles.done} onPress={onClose}>
<Text variant="label" color={colors.accentTextStrong}>
Done
</Text>
</Pressable>
</EqSheet>
);
}
const useStyles = createThemedStyles((colors) => ({
title: {
marginTop: spacing.xs,
marginBottom: spacing.md,
},
qrWrap: {
alignSelf: 'center',
padding: spacing.md,
borderRadius: radius.md,
backgroundColor: '#ffffff',
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.glassBorder,
},
name: {
alignSelf: 'center',
maxWidth: 260,
marginTop: spacing.md,
},
done: {
alignSelf: 'flex-end',
marginTop: spacing.lg,
paddingHorizontal: spacing.xl,
paddingVertical: spacing.md,
borderRadius: radius.pill,
backgroundColor: colors.accentGlow,
borderWidth: StyleSheet.hairlineWidth,
borderColor: colors.accent,
},
}));
export default EQPresetQrSheet;