diff --git a/apps/rebreak-native/app/(app)/chat.tsx b/apps/rebreak-native/app/(app)/chat.tsx
index 8c2209e..a257be1 100644
--- a/apps/rebreak-native/app/(app)/chat.tsx
+++ b/apps/rebreak-native/app/(app)/chat.tsx
@@ -4,6 +4,7 @@ import {
Text,
FlatList,
Pressable,
+ TouchableOpacity,
ActivityIndicator,
Image,
RefreshControl,
@@ -45,8 +46,7 @@ function DmItem({ conv, onPress }: { conv: DmConversation; onPress: () => void }
return (
- {({ pressed }) => (
-
+
{conv.partnerAvatar ? (
@@ -88,8 +88,7 @@ function DmItem({ conv, onPress }: { conv: DmConversation; onPress: () => void }
)}
-
- )}
+
);
}
@@ -150,19 +149,21 @@ export default function ChatScreen() {
{t('chat.title')}
{tab === 'groups' && (
- setCreateOpen(true)}
- style={({ pressed }) => [styles.createBtn, { opacity: pressed ? 0.7 : 1 }]}
+ activeOpacity={0.7}
+ style={styles.createBtn}
>
-
+
)}
{/* Tabs */}
- setTab('groups')}
+ activeOpacity={0.7}
style={[styles.tab, tab === 'groups' && styles.tabActive]}
>
{t('chat.groups')}
-
-
+ setTab('direct')}
+ activeOpacity={0.7}
style={[styles.tab, tab === 'direct' && styles.tabActive]}
>
{unreadDms}
)}
-
+
diff --git a/apps/rebreak-native/app/(app)/index.tsx b/apps/rebreak-native/app/(app)/index.tsx
index 9b55ecf..712dd3b 100644
--- a/apps/rebreak-native/app/(app)/index.tsx
+++ b/apps/rebreak-native/app/(app)/index.tsx
@@ -4,7 +4,7 @@ import {
Text,
ScrollView,
FlatList,
- Pressable,
+ TouchableOpacity,
RefreshControl,
ActivityIndicator,
} from 'react-native';
@@ -110,10 +110,10 @@ export default function HomeScreen() {
{/* Filter toggle */}
- setFilterOpen((o) => !o)}
+ activeOpacity={0.6}
className="flex-row items-center gap-1.5 self-start"
- style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}
>
f.value === activeCategory)?.label}
)}
-
+
{filterOpen && (
{
const active = activeCategory === f.value;
return (
- toggleFilter(f.value)}
- style={({ pressed }) => ({
- opacity: pressed ? 0.7 : 1,
+ activeOpacity={0.7}
+ style={{
flexDirection: 'row',
alignItems: 'center',
gap: 6,
@@ -151,7 +151,7 @@ export default function HomeScreen() {
borderWidth: 1,
backgroundColor: active ? colors.brandOrange : colors.surface,
borderColor: active ? colors.brandOrange : colors.border,
- })}
+ }}
>
{f.label}
-
+
);
})}
diff --git a/apps/rebreak-native/app/(app)/notifications.tsx b/apps/rebreak-native/app/(app)/notifications.tsx
index 8ceae8a..4f4018c 100644
--- a/apps/rebreak-native/app/(app)/notifications.tsx
+++ b/apps/rebreak-native/app/(app)/notifications.tsx
@@ -1,5 +1,5 @@
import { useEffect } from 'react';
-import { View, Text, FlatList, Pressable, RefreshControl } from 'react-native';
+import { View, Text, FlatList, TouchableOpacity, RefreshControl } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
@@ -31,12 +31,13 @@ export default function NotificationsScreen() {
return (
- router.back()}
+ activeOpacity={0.7}
style={{ width: 36, height: 36, borderRadius: 18, backgroundColor: colors.surfaceElevated, borderWidth: 1, borderColor: colors.border, alignItems: 'center', justifyContent: 'center' }}
>
-
+
@@ -91,11 +92,9 @@ function NotificationRow({
const colors = useColors();
const isUnread = !notif.readAt;
return (
- ({
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
>
)}
-
+
-
+
-
+
);
}
diff --git a/apps/rebreak-native/app/(auth)/confirm-otp.tsx b/apps/rebreak-native/app/(auth)/confirm-otp.tsx
index 604a6ad..0b84132 100644
--- a/apps/rebreak-native/app/(auth)/confirm-otp.tsx
+++ b/apps/rebreak-native/app/(auth)/confirm-otp.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
KeyboardAvoidingView,
Platform,
ActivityIndicator,
@@ -168,10 +168,11 @@ export default function ConfirmOtpScreen() {
)}
-
{loading ? (
@@ -179,11 +180,12 @@ export default function ConfirmOtpScreen() {
) : (
{t('auth.confirmBtn')}
)}
-
+
- 0 || loading}
+ activeOpacity={0.7}
className="py-3 items-center"
>
@@ -192,14 +194,15 @@ export default function ConfirmOtpScreen() {
{resendCooldown > 0 ? t('auth.resendCooldown', { seconds: resendCooldown }) : t('auth.resend')}
-
+
- router.back()}
+ activeOpacity={0.7}
className="py-3 items-center mt-2"
>
{t('auth.backToSignup')}
-
+
diff --git a/apps/rebreak-native/app/(auth)/confirm.tsx b/apps/rebreak-native/app/(auth)/confirm.tsx
index a0075cf..d6b78c0 100644
--- a/apps/rebreak-native/app/(auth)/confirm.tsx
+++ b/apps/rebreak-native/app/(auth)/confirm.tsx
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
-import { View, Text, Pressable, ActivityIndicator } from 'react-native';
+import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native';
import { useRouter, useLocalSearchParams } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useTranslation } from 'react-i18next';
@@ -82,12 +82,13 @@ export default function ConfirmScreen() {
) : (
<>
{errorMsg}
- router.replace('/signin')}
+ activeOpacity={0.7}
className="bg-neutral-100 border border-neutral-200 px-6 py-3 rounded-xl"
>
{t('auth.backToLoginPlain')}
-
+
>
)}
diff --git a/apps/rebreak-native/app/(auth)/device-limit.tsx b/apps/rebreak-native/app/(auth)/device-limit.tsx
index 7c91a5b..b270542 100644
--- a/apps/rebreak-native/app/(auth)/device-limit.tsx
+++ b/apps/rebreak-native/app/(auth)/device-limit.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { useRouter } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useTranslation } from 'react-i18next';
@@ -25,19 +25,21 @@ export default function DeviceLimitScreen() {
{/* TODO Phase 4: device management — list active devices + revoke button */}
- router.replace('/signin')}
- className="bg-rebreak-500 px-8 py-4 rounded-xl active:opacity-80"
+ activeOpacity={0.8}
+ className="bg-rebreak-500 px-8 py-4 rounded-xl"
>
{t('auth.toLogin')}
-
+
- router.push('/signin')}
+ activeOpacity={0.7}
className="py-3 mt-2"
>
{t('auth.deviceLimitUpgrade')}
-
+
);
diff --git a/apps/rebreak-native/app/(auth)/forgot-password.tsx b/apps/rebreak-native/app/(auth)/forgot-password.tsx
index 866be24..da69940 100644
--- a/apps/rebreak-native/app/(auth)/forgot-password.tsx
+++ b/apps/rebreak-native/app/(auth)/forgot-password.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
KeyboardAvoidingView,
Platform,
ActivityIndicator,
@@ -78,10 +78,11 @@ export default function ForgotPasswordScreen() {
)}
-
{loading ? (
@@ -89,7 +90,7 @@ export default function ForgotPasswordScreen() {
) : (
{t('auth.resetPasswordSend')}
)}
-
+
>
) : (
@@ -100,12 +101,13 @@ export default function ForgotPasswordScreen() {
)}
- router.back()}
+ activeOpacity={0.7}
className="py-4 items-center mt-2"
>
{t('auth.backToLogin')}
-
+
diff --git a/apps/rebreak-native/app/(auth)/signin.tsx b/apps/rebreak-native/app/(auth)/signin.tsx
index 5534de6..23b5eea 100644
--- a/apps/rebreak-native/app/(auth)/signin.tsx
+++ b/apps/rebreak-native/app/(auth)/signin.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
KeyboardAvoidingView,
Platform,
ScrollView,
@@ -100,10 +100,11 @@ export default function SignInScreen() {
{/* OAuth Buttons */}
- onOAuth('google')}
disabled={isLoading}
- className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 active:opacity-80 disabled:opacity-40"
+ activeOpacity={0.8}
+ className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'google' ? (
@@ -112,12 +113,13 @@ export default function SignInScreen() {
)}
{t('auth.googleSignin')}
-
+
- onOAuth('apple')}
disabled={isLoading}
- className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 active:opacity-80 disabled:opacity-40"
+ activeOpacity={0.8}
+ className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'apple' ? (
@@ -126,7 +128,7 @@ export default function SignInScreen() {
)}
{t('auth.appleSignin')}
-
+
{/* Divider */}
@@ -159,21 +161,23 @@ export default function SignInScreen() {
onChangeText={setPassword}
/>
- router.push('/forgot-password')}
+ activeOpacity={0.7}
className="self-end py-2 mb-4"
>
{t('auth.forgotPassword')}
-
+
{error && (
{error}
)}
-
{submitting ? (
@@ -181,17 +185,18 @@ export default function SignInScreen() {
) : (
{t('auth.signin')}
)}
-
+
- router.push('/signup')}
+ activeOpacity={0.7}
className="py-4 items-center mt-2"
>
{t('auth.noAccount')}{' '}
{t('auth.signup')}
-
+
diff --git a/apps/rebreak-native/app/(auth)/signup.tsx b/apps/rebreak-native/app/(auth)/signup.tsx
index 4b80b64..111bd42 100644
--- a/apps/rebreak-native/app/(auth)/signup.tsx
+++ b/apps/rebreak-native/app/(auth)/signup.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
KeyboardAvoidingView,
Platform,
ScrollView,
@@ -124,10 +124,11 @@ export default function SignUpScreen() {
{/* OAuth Buttons */}
- onOAuth('google')}
disabled={isLoading}
- className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 active:opacity-80 disabled:opacity-40"
+ activeOpacity={0.8}
+ className="flex-row items-center justify-center gap-3 bg-white border border-neutral-200 rounded-xl mb-3 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'google' ? (
@@ -136,12 +137,13 @@ export default function SignUpScreen() {
)}
{t('auth.googleSignup')}
-
+
- onOAuth('apple')}
disabled={isLoading}
- className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 active:opacity-80 disabled:opacity-40"
+ activeOpacity={0.8}
+ className="flex-row items-center justify-center gap-3 bg-neutral-900 rounded-xl mb-6 disabled:opacity-40"
style={{ paddingVertical: 14 }}
>
{oauthLoading === 'apple' ? (
@@ -150,7 +152,7 @@ export default function SignUpScreen() {
)}
{t('auth.appleSignup')}
-
+
{/* Divider */}
@@ -226,10 +228,11 @@ export default function SignUpScreen() {
{HERO_AVATARS.map((avatar) => {
const selected = avatar.id === avatarId;
return (
- setAvatarId(avatar.id)}
disabled={isLoading}
+ activeOpacity={0.7}
className={`rounded-full ${selected ? 'opacity-100' : 'opacity-40'}`}
>
-
+
);
})}
@@ -251,9 +254,10 @@ export default function SignUpScreen() {
{/* Terms Checkbox */}
- setTermsAccepted(!termsAccepted)}
disabled={isLoading}
+ activeOpacity={0.7}
className="flex-row items-start gap-3 mb-6"
>
{t('auth.termsLink')}
{t('auth.acceptTermsSuffix')}
-
+
-
{submitting ? (
@@ -283,17 +288,18 @@ export default function SignUpScreen() {
) : (
{t('auth.signupTitle')}
)}
-
+
- router.push('/signin')}
+ activeOpacity={0.7}
className="py-4 items-center mt-2"
>
{t('auth.alreadyRegistered')}{' '}
{t('auth.signin')}
-
+
diff --git a/apps/rebreak-native/app/debug.tsx b/apps/rebreak-native/app/debug.tsx
index fb3a2fc..1c6b68e 100644
--- a/apps/rebreak-native/app/debug.tsx
+++ b/apps/rebreak-native/app/debug.tsx
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
-import { View, Text, ScrollView, Pressable, Alert } from 'react-native';
+import { View, Text, ScrollView, TouchableOpacity, Alert } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
@@ -36,22 +36,14 @@ export default function DebugScreen() {
borderBottomColor: 'rgba(0,0,0,0.06)',
}}
>
- router.back()}
hitSlop={8}
- style={({ pressed }) => ({
- opacity: pressed ? 0.6 : 1,
- })}
+ activeOpacity={0.6}
+ style={{ width: 40, height: 40, alignItems: 'center', justifyContent: 'center' }}
>
-
-
-
-
+
+
Debug
@@ -214,18 +206,19 @@ function PlanOverrideToggle({
const isActive = plan === currentPlan;
const accent = PLAN_COLOR[plan];
return (
- switchPlan(plan)}
disabled={loading || isActive}
- style={({ pressed }) => ({
+ activeOpacity={0.7}
+ style={{
flex: 1,
paddingVertical: 10,
borderRadius: 10,
alignItems: 'center',
backgroundColor: isActive ? accent : colors.surfaceElevated,
- opacity: loading ? 0.5 : pressed ? 0.7 : 1,
- })}
+ opacity: loading ? 0.5 : 1,
+ }}
>
{plan}
-
+
);
})}
diff --git a/apps/rebreak-native/app/devices.tsx b/apps/rebreak-native/app/devices.tsx
index 0a26711..9e8a7ef 100644
--- a/apps/rebreak-native/app/devices.tsx
+++ b/apps/rebreak-native/app/devices.tsx
@@ -2,7 +2,6 @@ import {
ActivityIndicator,
Alert,
Platform,
- Pressable,
ScrollView,
Text,
TouchableOpacity,
@@ -222,13 +221,13 @@ function MobileDeviceRow({
{!device.isCurrent ? (
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
) : null}
);
@@ -324,12 +323,12 @@ function ProtectedDeviceRow({
onPressAction={({ nativeEvent: { event } }) => handleMenuSelect(event)}
shouldOpenOnLongPress={false}
>
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
);
@@ -579,19 +578,19 @@ export default function DevicesScreen() {
{t('devices.subtitle_legend')}
- ({
+
{t('devices.upgrade_cta')}
-
+
)}
diff --git a/apps/rebreak-native/app/dm.tsx b/apps/rebreak-native/app/dm.tsx
index 3fee143..24da0ff 100644
--- a/apps/rebreak-native/app/dm.tsx
+++ b/apps/rebreak-native/app/dm.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
FlatList,
- Pressable,
+ TouchableOpacity,
KeyboardAvoidingView,
Platform,
ActivityIndicator,
@@ -236,9 +236,9 @@ export default function DmScreen() {
{/* Header */}
- router.back()} hitSlop={8}>
+ router.back()} hitSlop={8} activeOpacity={0.7}>
-
+
{partner?.avatar ? (
diff --git a/apps/rebreak-native/app/games.tsx b/apps/rebreak-native/app/games.tsx
index c9a6d36..f8b00ac 100644
--- a/apps/rebreak-native/app/games.tsx
+++ b/apps/rebreak-native/app/games.tsx
@@ -1,5 +1,5 @@
import { useEffect, useState } from 'react';
-import { View, Text, Pressable, ScrollView } from 'react-native';
+import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
@@ -83,26 +83,17 @@ export default function GamesScreen() {
borderBottomColor: colors.border,
}}
>
- exit()}
hitSlop={10}
- style={({ pressed }) => ({
- opacity: pressed ? 0.6 : 1,
- })}
+ activeOpacity={0.6}
+ style={{ flexDirection: 'row', alignItems: 'center', gap: 4, paddingHorizontal: 6, paddingVertical: 6 }}
>
-
-
-
- {t('games.back_to_picker')}
-
-
-
+
+
+ {t('games.back_to_picker')}
+
+
{/* Title bewusst entfernt — der Game-Picker hat das Spiel schon ausgewählt,
Wiederholung im Header lenkt nur ab. Spacer balanciert den Back-Button. */}
@@ -141,22 +132,14 @@ export default function GamesScreen() {
borderBottomColor: colors.border,
}}
>
- router.back()}
hitSlop={8}
- style={({ pressed }) => ({
- opacity: pressed ? 0.6 : 1,
- })}
+ activeOpacity={0.6}
+ style={{ width: 40, height: 40, alignItems: 'center', justifyContent: 'center' }}
>
-
-
-
-
+
+
{t('games.title')}
diff --git a/apps/rebreak-native/app/index.tsx b/apps/rebreak-native/app/index.tsx
index eb3402e..dbd7fbf 100644
--- a/apps/rebreak-native/app/index.tsx
+++ b/apps/rebreak-native/app/index.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { useRouter } from 'expo-router';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useTranslation } from 'react-i18next';
@@ -15,12 +15,13 @@ export default function HomeScreen() {
{t('landing.tagline')}
- router.push('/signin')}
- className="bg-rebreak-500 px-8 py-4 rounded-full active:opacity-80"
+ activeOpacity={0.8}
+ className="bg-rebreak-500 px-8 py-4 rounded-full"
>
{t('landing.start')}
-
+
{t('landing.version')}
diff --git a/apps/rebreak-native/app/lyra.tsx b/apps/rebreak-native/app/lyra.tsx
index 24b8e18..a7532e7 100644
--- a/apps/rebreak-native/app/lyra.tsx
+++ b/apps/rebreak-native/app/lyra.tsx
@@ -9,7 +9,7 @@ import {
Text,
TextInput,
FlatList,
- Pressable,
+ TouchableOpacity,
Platform,
Animated,
Keyboard,
@@ -550,9 +550,9 @@ export default function CoachScreen() {
{/* Floating header — no bar, avatar + 2 icon buttons hover over chat */}
- router.replace('/(app)' as never)} hitSlop={12}>
+ router.replace('/(app)' as never)} hitSlop={12} activeOpacity={0.7}>
-
+
@@ -587,17 +587,17 @@ export default function CoachScreen() {
{t('coach.speaking')}
-
+
-
+
)}
-
+
-
+
{/* Content area */}
@@ -637,9 +637,9 @@ export default function CoachScreen() {
{/* Scroll-to-bottom button */}
{showScrollBtn && (
-
+
-
+
)}
)}
@@ -648,9 +648,9 @@ export default function CoachScreen() {
0 ? 8 : Math.max(12, insets.bottom), backgroundColor: colors.bg, borderTopColor: colors.border }]}>
{isRecording ? (
-
+
-
+
{formatDuration(recordingDuration)}
@@ -677,28 +677,30 @@ export default function CoachScreen() {
)}
{!isTranscribing && (
-
-
+
)}
{!isRecording && !isTranscribing && input.trim() !== '' && (
-
-
+
)}
diff --git a/apps/rebreak-native/app/profile/[userId].tsx b/apps/rebreak-native/app/profile/[userId].tsx
index 6c39bde..83d8563 100644
--- a/apps/rebreak-native/app/profile/[userId].tsx
+++ b/apps/rebreak-native/app/profile/[userId].tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { View, Text, ScrollView, Pressable, Image } from 'react-native';
+import { View, Text, ScrollView, TouchableOpacity, Image } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
@@ -119,13 +119,14 @@ export default function ForeignProfileScreen() {
paddingHorizontal: 12,
}}
>
- router.back()}
hitSlop={8}
- style={({ pressed }) => ({ opacity: pressed ? 0.5 : 1, padding: 8 })}
+ activeOpacity={0.5}
+ style={{ padding: 8 }}
>
-
+
Profil
@@ -204,15 +205,13 @@ export default function ForeignProfileScreen() {
- {
// TODO: POST /api/social/follow/[userId] resp. DELETE bei unfollow
setIsFollowing((v) => !v);
}}
- style={({ pressed }) => ({
- flex: 1,
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ flex: 1 }}
>
-
-
+ {
// TODO: navigate to DM with this userId
router.push(`/dm`);
}}
- style={({ pressed }) => ({
- flex: 1,
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ flex: 1 }}
>
-
+
diff --git a/apps/rebreak-native/app/profile/edit.tsx b/apps/rebreak-native/app/profile/edit.tsx
index 08caca6..e2020d0 100644
--- a/apps/rebreak-native/app/profile/edit.tsx
+++ b/apps/rebreak-native/app/profile/edit.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
ScrollView,
Image,
ActivityIndicator,
@@ -141,22 +141,22 @@ export default function ProfileEditScreen() {
backgroundColor: colors.bg,
}}
>
- router.back()}
hitSlop={10}
- style={({ pressed }) => ({ opacity: pressed ? 0.5 : 1, marginRight: 12 })}
+ activeOpacity={0.5}
+ style={{ marginRight: 12 }}
>
-
+
{t('profile.edit_title')}
- ({
- opacity: pressed || saving || !hasChanges || !nickname.trim() ? 0.4 : 1,
- })}
+ activeOpacity={0.4}
+ style={{ opacity: saving || !hasChanges || !nickname.trim() ? 0.4 : 1 }}
>
{saving ? (
@@ -171,7 +171,7 @@ export default function ProfileEditScreen() {
{t('profile.edit_save')}
)}
-
+
- ({
- marginTop: 12,
- flexDirection: 'row',
- alignItems: 'center',
- gap: 6,
- opacity: pressed ? 0.5 : 1,
- })}
+ activeOpacity={0.5}
+ style={{ marginTop: 12, flexDirection: 'row', alignItems: 'center', gap: 6 }}
>
{t('profile.edit_photo_cta')}
-
+
{/* Preset avatars */}
@@ -249,15 +244,13 @@ export default function ProfileEditScreen() {
{HERO_AVATARS.map((avatar) => {
const isSelected = !photoUri && avatarId === avatar.id;
return (
- {
setAvatarId(avatar.id);
setPhotoUri(null);
}}
- style={({ pressed }) => ({
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
>
-
+
);
})}
diff --git a/apps/rebreak-native/app/room.tsx b/apps/rebreak-native/app/room.tsx
index a092e31..2c0acbe 100644
--- a/apps/rebreak-native/app/room.tsx
+++ b/apps/rebreak-native/app/room.tsx
@@ -4,6 +4,7 @@ import {
Text,
FlatList,
Pressable,
+ TouchableOpacity,
Image,
Modal,
TextInput,
@@ -299,9 +300,9 @@ export default function RoomScreen() {
{/* Header */}
- router.back()} hitSlop={8}>
+ router.back()} hitSlop={8} activeOpacity={0.7}>
-
+
{room?.avatarUrl ? (
@@ -321,9 +322,9 @@ export default function RoomScreen() {
)}
- setSettingsOpen(true)} hitSlop={8}>
+ setSettingsOpen(true)} hitSlop={8} activeOpacity={0.7}>
-
+
{isLoading || !room ? (
@@ -342,20 +343,18 @@ export default function RoomScreen() {
{t('chat.join_pending')}
) : (
- [
- styles.joinBtn,
- { opacity: pressed || joining ? 0.7 : 1 },
- ]}
+ activeOpacity={0.7}
+ style={[styles.joinBtn, joining && { opacity: 0.7 }]}
>
{joining ? (
) : (
{t('chat.join')}
)}
-
+
)}
) : (
@@ -519,9 +518,9 @@ function RoomSettingsModal({
-
+
-
+
{t('chat.settings')}
@@ -529,8 +528,9 @@ function RoomSettingsModal({
{/* Avatar + Name */}
-
{room.avatarUrl ? (
@@ -545,7 +545,7 @@ function RoomSettingsModal({
)}
-
+
{room.name}
{room.description && {room.description}}
@@ -564,22 +564,24 @@ function RoomSettingsModal({
{req.nickname ?? 'Anonym'}
- handleRequest(req.userId, 'approve')}
+ activeOpacity={0.7}
>
{t('chat.approve')}
-
-
+ handleRequest(req.userId, 'reject')}
+ activeOpacity={0.7}
>
{t('chat.reject')}
-
+
))
)}
@@ -610,18 +612,20 @@ function RoomSettingsModal({
{isAdmin && m.role === 'member' && (
<>
- handlePromote(m.userId)}
+ activeOpacity={0.7}
>
Admin
-
-
+ handleBan(m.userId)}
+ activeOpacity={0.7}
>
Ban
-
+
>
)}
@@ -630,10 +634,10 @@ function RoomSettingsModal({
{/* Leave */}
{!room.isDefault && (
-
+
{t('chat.leave_room')}
-
+
)}
diff --git a/apps/rebreak-native/app/settings.tsx b/apps/rebreak-native/app/settings.tsx
index 8d84f60..7dd2bf7 100644
--- a/apps/rebreak-native/app/settings.tsx
+++ b/apps/rebreak-native/app/settings.tsx
@@ -2,9 +2,9 @@ import {
Alert,
Linking,
Platform,
- Pressable,
ScrollView,
Text,
+ TouchableOpacity,
View,
} from 'react-native';
import { useRef, useState } from 'react';
@@ -100,7 +100,7 @@ function SubscriptionSheet({ plan, colors, t }: SubscriptionSheetProps) {
{t('settings.subscription_sheet_body')}
- {
// TODO: für iOS-Submission ggf. zu nicht-tippbarem Text degradieren
// (Apple Guideline 3.1.1: externe Abo-Links können Review-Ablehnung triggern,
@@ -108,13 +108,13 @@ function SubscriptionSheet({ plan, colors, t }: SubscriptionSheetProps) {
// sollte ok sein, ist aber ungeprüft — bei Submission erneut prüfen.)
Linking.openURL('https://rebreak.org/account');
}}
- style={({ pressed }) => ({
+ activeOpacity={0.8}
+ style={{
backgroundColor: accentColor,
borderRadius: 14,
paddingVertical: 14,
alignItems: 'center',
- opacity: pressed ? 0.8 : 1,
- })}
+ }}
>
{t('settings.subscription_sheet_cta')}
-
+
);
}
@@ -472,9 +472,9 @@ export default function SettingsScreen() {
}
shouldOpenOnLongPress={false}
>
- ({ opacity: pressed ? 0.6 : 1 })}
+ activeOpacity={0.6}
>
-
+
);
}
- // Standard-Row: ganze Pressable als Tap-Target
return (
- ({
- opacity: row.soon ? 0.5 : pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ opacity: row.soon ? 0.5 : 1 }}
>
{rowLeft}
@@ -555,7 +553,7 @@ export default function SettingsScreen() {
/>
)}
-
+
);
})}
@@ -630,13 +628,13 @@ export default function SettingsScreen() {
{voiceOptions.map((opt, idx) => {
const isSelected = opt.value === selectedVoice;
return (
- {
setSelectedVoice(opt.value);
voiceSheetRef.current?.dismiss();
}}
- style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1 })}
+ activeOpacity={0.6}
>
) : null}
-
+
);
})}
diff --git a/apps/rebreak-native/app/urge.tsx b/apps/rebreak-native/app/urge.tsx
index f8910de..e7ece2f 100644
--- a/apps/rebreak-native/app/urge.tsx
+++ b/apps/rebreak-native/app/urge.tsx
@@ -1227,11 +1227,7 @@ export default function SOSScreen() {
key={chip.action}
onPress={() => handleChip(chip.action)}
disabled={thinking}
- style={({ pressed }) => [
- st.chip,
- pressed && st.chipPressed,
- thinking && { opacity: 0.4 },
- ]}
+ style={[st.chip, thinking && { opacity: 0.4 }]}
>
{iconName && }
diff --git a/apps/rebreak-native/components/ComposeCard.tsx b/apps/rebreak-native/components/ComposeCard.tsx
index afa1035..24f462e 100644
--- a/apps/rebreak-native/components/ComposeCard.tsx
+++ b/apps/rebreak-native/components/ComposeCard.tsx
@@ -4,6 +4,7 @@ import {
Text,
TextInput,
Pressable,
+ TouchableOpacity,
Image,
ActivityIndicator,
Alert,
@@ -133,7 +134,6 @@ export function ComposeCard({ onPosted }: Props) {
hitSlop={{ top: 9, bottom: 9, left: 9, right: 9 }}
android_ripple={{ color: 'rgba(255,255,255,0.18)', borderless: true, radius: 22 }}
className="absolute top-2 right-2 w-7 h-7 rounded-full bg-black/50 items-center justify-center"
- style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
>
@@ -148,34 +148,33 @@ export function ComposeCard({ onPosted }: Props) {
onPress={pickImage}
android_ripple={{ color: 'rgba(0,0,0,0.08)', borderless: true, radius: 22 }}
className="flex-row items-center gap-1.5 px-2"
- style={({ pressed }) => ({ opacity: pressed ? 0.6 : 1, height: 44 })}
+ style={{ height: 44 }}
>
{t('community.image')}
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
{t('common.cancel')}
-
- { if (!content.trim() || posting) return; submit(); }}
+
+ { if (!content.trim() || posting) return; submit(); }}
disabled={!content.trim() || posting}
+ activeOpacity={0.5}
className="bg-rebreak-500 items-center justify-center rounded-full px-5 h-8"
- style={({ pressed }) => ({
- opacity: pressed || !content.trim() || posting ? 0.5 : 1,
- })}
+ style={{ opacity: !content.trim() || posting ? 0.5 : 1 }}
>
{posting ? (
) : (
{t('community.share')}
)}
-
+
)}
diff --git a/apps/rebreak-native/components/ConfirmAlert.tsx b/apps/rebreak-native/components/ConfirmAlert.tsx
index 9d502dd..fe783bf 100644
--- a/apps/rebreak-native/components/ConfirmAlert.tsx
+++ b/apps/rebreak-native/components/ConfirmAlert.tsx
@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react';
-import { Modal, View, Text, Pressable, Animated, Easing } from 'react-native';
+import { Modal, View, Text, TouchableOpacity, Animated, Easing } from 'react-native';
// Wichtig (UX-Entscheidung 2026-05-05): Icon im Confirm-Modal NICHT animieren —
// User sieht zwei Modals nacheinander (Confirm → Success), beide animierte Icons
// = visuelle Doppel-Eskalation, wirkt verwirrend. Daher: Card animiert auf,
@@ -74,7 +74,8 @@ export function ConfirmAlert({
return (
-
- {}} style={{ width: '85%', maxWidth: 340 }}>
+ {}} style={{ width: '85%', maxWidth: 340 }}>
-
{resolvedCancelLabel}
-
+
-
{resolvedConfirmLabel}
-
+
-
-
+
+
);
}
diff --git a/apps/rebreak-native/components/DeviceLimitReachedSheet.tsx b/apps/rebreak-native/components/DeviceLimitReachedSheet.tsx
index 29f8375..08dba52 100644
--- a/apps/rebreak-native/components/DeviceLimitReachedSheet.tsx
+++ b/apps/rebreak-native/components/DeviceLimitReachedSheet.tsx
@@ -1,4 +1,4 @@
-import { ActivityIndicator, Platform, Pressable, Text, View } from 'react-native';
+import { ActivityIndicator, Platform, TouchableOpacity, Text, View } from 'react-native';
import { useEffect, useRef, useState } from 'react';
import { TrueSheet, type SheetDetent } from '@lodev09/react-native-true-sheet';
import { Ionicons } from '@expo/vector-icons';
@@ -106,13 +106,13 @@ function DeviceLimitRow({
{removing ? (
) : (
- onRemove(device.id)}
hitSlop={8}
- style={({ pressed }) => ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
)}
);
diff --git a/apps/rebreak-native/components/KeyboardAwareSheet.tsx b/apps/rebreak-native/components/KeyboardAwareSheet.tsx
index 85d33e1..c89d0a8 100644
--- a/apps/rebreak-native/components/KeyboardAwareSheet.tsx
+++ b/apps/rebreak-native/components/KeyboardAwareSheet.tsx
@@ -5,7 +5,7 @@ import {
Keyboard,
Modal,
Platform,
- Pressable,
+ TouchableOpacity,
StyleProp,
View,
ViewStyle,
@@ -162,7 +162,7 @@ export function KeyboardAwareSheet({
opacity: backdropOpacity,
}}
>
- {dismissOnBackdrop && }
+ {dismissOnBackdrop && }
{/* Outer: animated height (JS-driver) */}
diff --git a/apps/rebreak-native/components/NotificationsDropdown.tsx b/apps/rebreak-native/components/NotificationsDropdown.tsx
index 529beb9..39da854 100644
--- a/apps/rebreak-native/components/NotificationsDropdown.tsx
+++ b/apps/rebreak-native/components/NotificationsDropdown.tsx
@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react';
-import { View, Text, Pressable, Modal, FlatList, Animated, Image } from 'react-native';
+import { View, Text, Pressable, TouchableOpacity, Modal, FlatList, Animated, Image } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useRouter, type RelativePathString } from 'expo-router';
import { useTranslation } from 'react-i18next';
@@ -239,11 +239,9 @@ function NotificationRow({
const avatarUrl = isSocial ? resolveAvatar(notif.actorAvatar, notif.actorName) : null;
return (
- ({
- opacity: pressed ? 0.65 : 1,
- })}
+ activeOpacity={0.65}
>
-
+
);
}
diff --git a/apps/rebreak-native/components/OptionsBottomSheet.tsx b/apps/rebreak-native/components/OptionsBottomSheet.tsx
index 7586724..2e08b16 100644
--- a/apps/rebreak-native/components/OptionsBottomSheet.tsx
+++ b/apps/rebreak-native/components/OptionsBottomSheet.tsx
@@ -18,6 +18,7 @@ import {
View,
Text,
Pressable,
+ TouchableOpacity,
Animated,
Easing,
} from 'react-native';
@@ -177,15 +178,13 @@ export function OptionsBottomSheet({
const isSelected =
value !== null && value !== undefined && opt.value === value;
return (
- {
onSelect(opt.value);
close();
}}
- style={({ pressed }) => ({
- backgroundColor: pressed ? 'rgba(0,0,0,0.06)' : 'transparent',
- })}
+ activeOpacity={0.7}
>
({
{opt.label}
-
+
);
})}
{/* Cancel-Card — separat, bold */}
-
- {({ pressed }) => (
-
+
+
-
- Abbrechen
-
-
- )}
-
+ Abbrechen
+
+
+
);
diff --git a/apps/rebreak-native/components/PostCard.tsx b/apps/rebreak-native/components/PostCard.tsx
index e69e1a5..8b6e6ce 100644
--- a/apps/rebreak-native/components/PostCard.tsx
+++ b/apps/rebreak-native/components/PostCard.tsx
@@ -275,7 +275,6 @@ function PostCardImpl({ post, onCommentPress }: Props) {
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
android_ripple={{ color: 'rgba(220,38,38,0.12)', borderless: true, radius: 22 }}
className="flex-row items-center gap-1.5"
- style={({ pressed }) => ({ opacity: pressed ? 0.5 : 1, transform: [{ scale: pressed ? 0.94 : 1 }] })}
>
({ opacity: pressed ? 0.5 : 1, transform: [{ scale: pressed ? 0.94 : 1 }] })}
>
{post.commentsCount > 0 && (
@@ -514,7 +512,7 @@ function DomainVoteCard({
onPress={() => onVote('yes')}
disabled={voting}
className="flex-1 flex-row items-center justify-center gap-1.5 h-9 rounded-xl border border-rebreak-500"
- style={({ pressed }) => ({ opacity: pressed || voting ? 0.5 : 1 })}
+ style={{ opacity: voting ? 0.5 : 1 }}
>
@@ -525,7 +523,7 @@ function DomainVoteCard({
onPress={() => onVote('no')}
disabled={voting}
className="flex-1 flex-row items-center justify-center gap-1.5 h-9 rounded-xl border border-neutral-300"
- style={({ pressed }) => ({ opacity: pressed || voting ? 0.5 : 1 })}
+ style={{ opacity: voting ? 0.5 : 1 }}
>
diff --git a/apps/rebreak-native/components/PostCommentsSheet.tsx b/apps/rebreak-native/components/PostCommentsSheet.tsx
index 88bb00d..5faf3bd 100644
--- a/apps/rebreak-native/components/PostCommentsSheet.tsx
+++ b/apps/rebreak-native/components/PostCommentsSheet.tsx
@@ -6,6 +6,7 @@ import {
FlatList,
TextInput,
Pressable,
+ TouchableOpacity,
Keyboard,
Platform,
ActivityIndicator,
@@ -393,12 +394,11 @@ export function PostCommentsSheet({ postId, visible, onClose }: Props) {
onSubmitEditing={submit}
blurOnSubmit={false}
/>
- ({
- opacity: pressed || !text.trim() || submitting ? 0.5 : 1,
- })}
+ activeOpacity={0.5}
+ style={{ opacity: !text.trim() || submitting ? 0.5 : 1 }}
>
)}
-
+
diff --git a/apps/rebreak-native/components/SuccessAlert.tsx b/apps/rebreak-native/components/SuccessAlert.tsx
index 5185b7e..0cecf1b 100644
--- a/apps/rebreak-native/components/SuccessAlert.tsx
+++ b/apps/rebreak-native/components/SuccessAlert.tsx
@@ -1,5 +1,5 @@
import { useEffect, useRef } from 'react';
-import { Modal, View, Text, Pressable, Animated, Easing } from 'react-native';
+import { Modal, View, Text, TouchableOpacity, Animated, Easing } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
@@ -73,7 +73,8 @@ export function SuccessAlert({ visible, title, message, onClose }: Props) {
return (
{/* Backdrop — Pressable damit Tap-outside schließt */}
-
{/* Card — Pressable mit onPress={()=>{}} damit Tap auf Card NICHT bubbelt
* zum Backdrop und das Modal schließt. */}
- {}} style={{ width: '85%', maxWidth: 320 }}>
+ {}} style={{ width: '85%', maxWidth: 320 }}>
)}
-
{t('common.ok')}
-
+
-
-
+
+
);
}
diff --git a/apps/rebreak-native/components/WheelPickerModal.tsx b/apps/rebreak-native/components/WheelPickerModal.tsx
index 8b2ee81..4f9b05e 100644
--- a/apps/rebreak-native/components/WheelPickerModal.tsx
+++ b/apps/rebreak-native/components/WheelPickerModal.tsx
@@ -12,7 +12,7 @@
* Für kurze Listen (3-7 items) bleibt ActionSheet besser (siehe useNativeActionSheet).
*/
import { useEffect, useState } from 'react';
-import { Modal, View, Text, Pressable } from 'react-native';
+import { Modal, View, Text, Pressable, TouchableOpacity } from 'react-native';
import { Picker } from '@react-native-picker/picker';
import { useColors } from '../lib/theme';
@@ -91,7 +91,7 @@ export function WheelPickerModal({
borderBottomColor: colors.border,
}}
>
-
+
({
>
Abbrechen
-
+
({
>
{title}
-
+
({
>
Fertig
-
+
{/* Wheel — native iOS UIPickerView */}
diff --git a/apps/rebreak-native/components/blocker/AddDomainSheet.tsx b/apps/rebreak-native/components/blocker/AddDomainSheet.tsx
index 25eb27c..ca4d351 100644
--- a/apps/rebreak-native/components/blocker/AddDomainSheet.tsx
+++ b/apps/rebreak-native/components/blocker/AddDomainSheet.tsx
@@ -4,6 +4,7 @@ import {
Text,
TextInput,
Pressable,
+ TouchableOpacity,
Image,
ActivityIndicator,
} from 'react-native';
@@ -262,13 +263,11 @@ export function AddDomainSheet({ visible, tier, onClose, onAdd }: Props) {
{/* Add-Button */}
- ({
- opacity: pressed ? 0.85 : 1,
- marginBottom: insets.bottom > 0 ? 8 : 12,
- })}
+ activeOpacity={0.85}
+ style={{ marginBottom: insets.bottom > 0 ? 8 : 12 }}
>
)}
-
+
);
diff --git a/apps/rebreak-native/components/blocker/CooldownBanner.tsx b/apps/rebreak-native/components/blocker/CooldownBanner.tsx
index 4c294d1..a86c689 100644
--- a/apps/rebreak-native/components/blocker/CooldownBanner.tsx
+++ b/apps/rebreak-native/components/blocker/CooldownBanner.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable, ActivityIndicator } from 'react-native';
+import { View, Text, TouchableOpacity, ActivityIndicator } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -52,13 +52,12 @@ export function CooldownBanner({ remainingFormatted, onCancel }: Props) {
{remainingFormatted}
- ({
- opacity: pressed || cancelling ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ opacity: cancelling ? 0.7 : 1 }}
>
)}
-
+
);
}
diff --git a/apps/rebreak-native/components/blocker/DeactivationExplainerSheet.tsx b/apps/rebreak-native/components/blocker/DeactivationExplainerSheet.tsx
index df8c4ab..8b462c2 100644
--- a/apps/rebreak-native/components/blocker/DeactivationExplainerSheet.tsx
+++ b/apps/rebreak-native/components/blocker/DeactivationExplainerSheet.tsx
@@ -1,4 +1,4 @@
-import { Modal, View, Text, Pressable, ScrollView, ActionSheetIOS, Platform, Alert } from 'react-native';
+import { Modal, View, Text, Pressable, TouchableOpacity, ScrollView, ActionSheetIOS, Platform, Alert } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
@@ -138,11 +138,9 @@ export function DeactivationExplainerSheet({
{/* Primary Deflector */}
- ({
- opacity: pressed ? 0.85 : 1,
- })}
+ activeOpacity={0.85}
>
-
+
{/* Destructive secondary */}
- ({
- opacity: pressed || submitting ? 0.5 : 1,
+ activeOpacity={0.5}
+ style={{
+ opacity: submitting ? 0.5 : 1,
alignSelf: 'center',
paddingVertical: 12,
- })}
+ }}
>
{submitting ? t('blocker.deactivation_starting') : t('blocker.deactivation_start_anyway')}
-
+
diff --git a/apps/rebreak-native/components/blocker/DomainGrid.tsx b/apps/rebreak-native/components/blocker/DomainGrid.tsx
index 7e50b80..a6eb570 100644
--- a/apps/rebreak-native/components/blocker/DomainGrid.tsx
+++ b/apps/rebreak-native/components/blocker/DomainGrid.tsx
@@ -3,6 +3,7 @@ import {
View,
Text,
Pressable,
+ TouchableOpacity,
Image,
ActivityIndicator,
} from 'react-native';
@@ -138,11 +139,9 @@ export function DomainGrid({ domains, tier, onAdd, onSubmit, onUpgradePro }: Pro
{/* Limit-Reached Upsell (nur Free) */}
{tier.atLimit && tier.plan === 'free' && (
- ({
- opacity: pressed ? 0.85 : 1,
- })}
+ activeOpacity={0.85}
>
-
+
)}
{/* Empty State */}
diff --git a/apps/rebreak-native/components/blocker/ProtectionCard.tsx b/apps/rebreak-native/components/blocker/ProtectionCard.tsx
index d4a4088..de4f65f 100644
--- a/apps/rebreak-native/components/blocker/ProtectionCard.tsx
+++ b/apps/rebreak-native/components/blocker/ProtectionCard.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Switch, Pressable, ActivityIndicator } from 'react-native';
+import { View, Text, Switch, TouchableOpacity, ActivityIndicator } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
import type { ProtectionState } from '../../lib/protection';
@@ -89,12 +89,10 @@ export function ProtectionCard({ state, loading, onActivate, onPressSettings }:
{loading ? (
) : isActive ? (
- ({
- opacity: pressed ? 0.6 : 1,
- })}
+ activeOpacity={0.6}
accessibilityLabel={t('blocker.protection_settings_a11y')}
>
-
+
) : (
- {/* MEHR INFO – outline button: Pressable=card, inner View=flex-row */}
- ({
- marginTop: 4,
- opacity: pressed ? 0.75 : 1,
- })}
+ activeOpacity={0.75}
+ style={{ marginTop: 4 }}
>
-
+
@@ -676,11 +675,9 @@ function FaqItem({ question, answer }: { question: string; answer: string }) {
backgroundColor: colors.bg,
}}
>
- setOpen((v) => !v)}
- style={({ pressed }) => ({
- opacity: pressed ? 0.75 : 1,
- })}
+ activeOpacity={0.75}
>
@@ -702,7 +699,7 @@ function FaqItem({ question, answer }: { question: string; answer: string }) {
-
+
{open && (
diff --git a/apps/rebreak-native/components/blocker/ProtectionLockedCard.tsx b/apps/rebreak-native/components/blocker/ProtectionLockedCard.tsx
index fe369a7..74d952f 100644
--- a/apps/rebreak-native/components/blocker/ProtectionLockedCard.tsx
+++ b/apps/rebreak-native/components/blocker/ProtectionLockedCard.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
import type { ProtectionState } from '../../lib/protection';
@@ -74,12 +74,10 @@ export function ProtectionLockedCard({ state, onPressSettings }: Props) {
- ({
- opacity: pressed ? 0.6 : 1,
- })}
+ activeOpacity={0.6}
accessibilityLabel={t('blocker.protection_settings_a11y')}
>
-
+
{/* Stats nur wenn aktiv und kein Cooldown */}
diff --git a/apps/rebreak-native/components/chat/ChatBubble.tsx b/apps/rebreak-native/components/chat/ChatBubble.tsx
index 67a9ea5..2315da0 100644
--- a/apps/rebreak-native/components/chat/ChatBubble.tsx
+++ b/apps/rebreak-native/components/chat/ChatBubble.tsx
@@ -3,6 +3,7 @@ import {
View,
Text,
Pressable,
+ TouchableOpacity,
Image,
StyleSheet,
Modal,
@@ -127,10 +128,11 @@ export function ChatBubble({
>
{/* Reply preview */}
{msg.replyTo && (
- {
/* could implement scroll-to */
}}
+ activeOpacity={0.7}
style={[
styles.replyPreview,
{
@@ -163,13 +165,14 @@ export function ChatBubble({
)}{' '}
{msg.replyTo.content || (replyHasAttachment ? t('chat.image_attachment') : '…')}
-
+
)}
{/* Image attachment */}
{msg.attachmentUrl && msg.attachmentType === 'image' && (
- onOpenImage(msg.attachmentUrl!)}
+ activeOpacity={0.7}
style={[styles.imageWrap, msg.content ? { marginBottom: 4 } : null]}
>
{formatTime(msg.createdAt)}
)}
-
+
)}
{/* File attachment */}
@@ -284,25 +287,27 @@ export function ChatBubble({
animationType="fade"
onRequestClose={() => setActionsOpen(false)}
>
- setActionsOpen(false)}>
+ setActionsOpen(false)} activeOpacity={1}>
{}}>
- {
setActionsOpen(false);
onReply(msg);
}}
+ activeOpacity={0.7}
>
{t('chat.reply')}
-
-
+ {
setActionsOpen(false);
onLike(msg);
}}
+ activeOpacity={0.7}
>
{msg.likedByMe ? t('chat.unlike') : t('chat.like')}
-
+
{msg.content !== '' && (
-
+
{t('chat.copy')}
-
+
)}
-
+
>
);
diff --git a/apps/rebreak-native/components/chat/ChatInput.tsx b/apps/rebreak-native/components/chat/ChatInput.tsx
index 9c3ef5e..63c5e9a 100644
--- a/apps/rebreak-native/components/chat/ChatInput.tsx
+++ b/apps/rebreak-native/components/chat/ChatInput.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
Image,
StyleSheet,
ActivityIndicator,
@@ -155,9 +155,9 @@ export function ChatInput({
{replyTo.content || '…'}
-
+
-
+
)}
@@ -174,21 +174,22 @@ export function ChatInput({
{attachment.name}
-
+
-
+
)}
{/* Input row */}
-
-
+
-
)}
-
+
);
diff --git a/apps/rebreak-native/components/chat/CreateRoomSheet.tsx b/apps/rebreak-native/components/chat/CreateRoomSheet.tsx
index 4744cfa..31a9da2 100644
--- a/apps/rebreak-native/components/chat/CreateRoomSheet.tsx
+++ b/apps/rebreak-native/components/chat/CreateRoomSheet.tsx
@@ -3,7 +3,7 @@ import {
View,
Text,
TextInput,
- Pressable,
+ TouchableOpacity,
StyleSheet,
ActivityIndicator,
} from 'react-native';
@@ -96,12 +96,12 @@ export function CreateRoomSheet({ visible, onClose, onCreated }: Props) {
/>
{/* Public toggle */}
- setIsPublic((v) => !v)}>
+ setIsPublic((v) => !v)}>
{t('chat.public_room')}
-
+
{/* Join mode (private only) */}
{!isPublic && (
@@ -109,8 +109,9 @@ export function CreateRoomSheet({ visible, onClose, onCreated }: Props) {
{t('chat.join_mode')}
{(['approval', 'invite_only'] as const).map((mode) => (
- setJoinMode(mode)}
>
@@ -122,7 +123,7 @@ export function CreateRoomSheet({ visible, onClose, onCreated }: Props) {
>
{t(`chat.join_mode_${mode === 'approval' ? 'approval' : 'invite'}`)}
-
+
))}
@@ -132,10 +133,11 @@ export function CreateRoomSheet({ visible, onClose, onCreated }: Props) {
{/* Actions */}
-
+
{t('common.cancel')}
-
-
+ {t('chat.create')}
)}
-
+
diff --git a/apps/rebreak-native/components/chat/RoomCard.tsx b/apps/rebreak-native/components/chat/RoomCard.tsx
index 5ef7e86..ef7d66f 100644
--- a/apps/rebreak-native/components/chat/RoomCard.tsx
+++ b/apps/rebreak-native/components/chat/RoomCard.tsx
@@ -40,8 +40,7 @@ export function RoomCard({ room, onPress }: Props) {
return (
- {({ pressed }) => (
-
+
-
- )}
+
);
}
diff --git a/apps/rebreak-native/components/devices/AddMacSheet.tsx b/apps/rebreak-native/components/devices/AddMacSheet.tsx
index 9867d6d..8beb231 100644
--- a/apps/rebreak-native/components/devices/AddMacSheet.tsx
+++ b/apps/rebreak-native/components/devices/AddMacSheet.tsx
@@ -2,7 +2,7 @@ import {
ActivityIndicator,
Alert,
Linking,
- Pressable,
+ TouchableOpacity,
Text,
TextInput,
View,
@@ -140,13 +140,13 @@ export function AddMacSheet({
? t('devices.download_button')
: t('devices.success_title')}
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
}
>
@@ -221,16 +221,17 @@ function Step1LabelContent({
) : null}
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
alignItems: 'center',
- opacity: pressed || enrolling ? 0.7 : 1,
- })}
+ opacity: enrolling ? 0.7 : 1,
+ }}
>
{enrolling ? (
@@ -239,7 +240,7 @@ function Step1LabelContent({
{t('devices.prepare_profile')}
)}
-
+
);
}
@@ -330,9 +331,10 @@ function Step2OnboardingContent({
{/* Download button */}
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
@@ -340,27 +342,27 @@ function Step2OnboardingContent({
flexDirection: 'row',
justifyContent: 'center',
gap: 8,
- opacity: pressed ? 0.7 : 1,
- })}
+ }}
>
{t('devices.download_button')}
-
+
{/* Confirm installed */}
- ({
+ activeOpacity={0.7}
+ style={{
borderWidth: 1.5,
borderColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 14,
alignItems: 'center',
- opacity: pressed || confirming ? 0.7 : 1,
- })}
+ opacity: confirming ? 0.7 : 1,
+ }}
>
{confirming ? (
@@ -369,12 +371,13 @@ function Step2OnboardingContent({
{t('devices.confirm_installed')}
)}
-
+
{/* Need help */}
- ({ opacity: pressed ? 0.5 : 1, alignItems: 'center' })}
+ activeOpacity={0.5}
+ style={{ alignItems: 'center' }}
>
{t('devices.need_help')}
-
+
);
}
@@ -436,22 +439,22 @@ function Step3SuccessContent({
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
paddingHorizontal: 40,
alignItems: 'center',
- opacity: pressed ? 0.7 : 1,
alignSelf: 'stretch',
- })}
+ }}
>
{t('common.ok')}
-
+
);
}
diff --git a/apps/rebreak-native/components/devices/AddWindowsSheet.tsx b/apps/rebreak-native/components/devices/AddWindowsSheet.tsx
index ced504f..5935c19 100644
--- a/apps/rebreak-native/components/devices/AddWindowsSheet.tsx
+++ b/apps/rebreak-native/components/devices/AddWindowsSheet.tsx
@@ -2,7 +2,7 @@ import {
ActivityIndicator,
Alert,
Linking,
- Pressable,
+ TouchableOpacity,
Text,
TextInput,
View,
@@ -141,13 +141,13 @@ export function AddWindowsSheet({
? t('devices.windows_download_button')
: t('devices.windows_success_title')}
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
}
>
@@ -228,16 +228,17 @@ function WindowsStep1LabelContent({
) : null}
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
alignItems: 'center',
- opacity: pressed || enrolling ? 0.7 : 1,
- })}
+ opacity: enrolling ? 0.7 : 1,
+ }}
>
{enrolling ? (
@@ -246,7 +247,7 @@ function WindowsStep1LabelContent({
{t('devices.prepare_profile')}
)}
-
+
);
}
@@ -337,9 +338,10 @@ function WindowsStep2OnboardingContent({
{/* Download button */}
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
@@ -347,27 +349,27 @@ function WindowsStep2OnboardingContent({
flexDirection: 'row',
justifyContent: 'center',
gap: 8,
- opacity: pressed ? 0.7 : 1,
- })}
+ }}
>
{t('devices.windows_download_button')}
-
+
{/* Confirm installed */}
- ({
+ activeOpacity={0.7}
+ style={{
borderWidth: 1.5,
borderColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 14,
alignItems: 'center',
- opacity: pressed || confirming ? 0.7 : 1,
- })}
+ opacity: confirming ? 0.7 : 1,
+ }}
>
{confirming ? (
@@ -376,12 +378,13 @@ function WindowsStep2OnboardingContent({
{t('devices.confirm_installed')}
)}
-
+
{/* Need help */}
- ({ opacity: pressed ? 0.5 : 1, alignItems: 'center' })}
+ activeOpacity={0.5}
+ style={{ alignItems: 'center' }}
>
{t('devices.need_help')}
-
+
);
}
@@ -443,22 +446,22 @@ function WindowsStep3SuccessContent({
- ({
+ activeOpacity={0.7}
+ style={{
backgroundColor: colors.brandOrange,
borderRadius: 14,
paddingVertical: 16,
paddingHorizontal: 40,
alignItems: 'center',
- opacity: pressed ? 0.7 : 1,
alignSelf: 'stretch',
- })}
+ }}
>
{t('common.ok')}
-
+
);
}
diff --git a/apps/rebreak-native/components/games/GameCard.tsx b/apps/rebreak-native/components/games/GameCard.tsx
index 6b4c1f7..5742ffc 100644
--- a/apps/rebreak-native/components/games/GameCard.tsx
+++ b/apps/rebreak-native/components/games/GameCard.tsx
@@ -1,6 +1,6 @@
// RN-Port der Vue-Card aus apps/rebreak/app/components/urge/UrgeGamePicker.vue
// 2x2-Grid-Kachel mit SVG-Icon (56x56), Titel, descKey und Star-Rating.
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { SvgXml } from 'react-native-svg';
import { useTranslation } from 'react-i18next';
import { GameRatingStars } from './GameRatingStars';
@@ -27,13 +27,10 @@ export function GameCard({
}: GameCardProps) {
const { t } = useTranslation();
return (
- onPress(id)}
- style={({ pressed }) => ({
- width: '100%',
- transform: [{ scale: pressed ? 0.97 : 1 }],
- opacity: pressed ? 0.85 : 1,
- })}
+ activeOpacity={0.85}
+ style={{ width: '100%' }}
>
-
+
);
}
diff --git a/apps/rebreak-native/components/games/StarRating.tsx b/apps/rebreak-native/components/games/StarRating.tsx
index 271f761..4517dda 100644
--- a/apps/rebreak-native/components/games/StarRating.tsx
+++ b/apps/rebreak-native/components/games/StarRating.tsx
@@ -1,6 +1,6 @@
// RN-Port von apps/rebreak/app/components/StarRating.vue
// Unterstützt fractional values (z.B. 3.7) via width-clipping.
-import { View, Pressable } from 'react-native';
+import { View, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useState } from 'react';
@@ -83,15 +83,14 @@ export function StarRating({
if (interactive) {
stars.push(
- onChange?.(i)}
- onHoverIn={() => setHover(i)}
- onHoverOut={() => setHover(0)}
hitSlop={4}
+ activeOpacity={0.7}
>
{star}
-
+
);
} else {
stars.push(star);
diff --git a/apps/rebreak-native/components/header/HeaderDropdownMenu.tsx b/apps/rebreak-native/components/header/HeaderDropdownMenu.tsx
index 01a41de..6bfb8e6 100644
--- a/apps/rebreak-native/components/header/HeaderDropdownMenu.tsx
+++ b/apps/rebreak-native/components/header/HeaderDropdownMenu.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable, Modal } from 'react-native';
+import { View, Text, Pressable, TouchableOpacity, Modal } from 'react-native';
import { useRouter, type RelativePathString } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
@@ -166,14 +166,13 @@ export function HeaderDropdownMenu({ visible, onClose, topOffset = 80 }: Props)
{/* Profile · Settings · Games · [Debug DEV] */}
{items.map((item) => (
- {
onClose();
void item.onSelect();
}}
- android_ripple={{ color: colors.surfaceElevated }}
- style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })}
+ activeOpacity={0.7}
>
-
+
))}
{/* Abmelden — neutral, nicht rot */}
- ({ opacity: pressed ? 0.7 : 1 })}
+ activeOpacity={0.7}
>
-
+
diff --git a/apps/rebreak-native/components/mail/ConnectMailSheet.tsx b/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
index 664b399..1855956 100644
--- a/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
+++ b/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
@@ -2,7 +2,7 @@ import { useState } from 'react';
import {
ActivityIndicator,
Linking,
- Pressable,
+ TouchableOpacity,
ScrollView,
Text,
TextInput,
@@ -164,17 +164,17 @@ export function ConnectMailSheet({ visible, onClose, onSuccess }: Props) {
}}
>
{view === 'form' ? (
-
+
{t('common.back')}
-
+
) : (
-
+
{t('common.cancel')}
-
+
)}
{view === 'form' && currentProvider
@@ -250,13 +250,11 @@ function ProviderGrid({
{providers.map((p) => (
- onSelect(p)}
- style={({ pressed }) => ({
- width: '47%',
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ width: '47%' }}
>
-
+
))}
@@ -376,7 +374,7 @@ function FormView({
{t(provider.guideKey)}
{provider.guideUrl.length > 0 && (
- Linking.openURL(provider.guideUrl)}>
+ Linking.openURL(provider.guideUrl)}>
{t('mail.app_password_open_link')} →
-
+
)}
@@ -460,7 +458,8 @@ function FormView({
color: colors.text,
}}
/>
-
-
+
@@ -520,14 +519,11 @@ function FormView({
)}
{/* Connect-Button */}
- ({
- opacity: pressed ? 0.85 : 1,
- marginTop: 4,
- marginBottom: insets.bottom > 0 ? 8 : 12,
- })}
+ style={{ marginTop: 4, marginBottom: insets.bottom > 0 ? 8 : 12 }}
>
)}
-
+
);
}
diff --git a/apps/rebreak-native/components/mail/EditMailAccountSheet.tsx b/apps/rebreak-native/components/mail/EditMailAccountSheet.tsx
index 55e3c84..e0d11aa 100644
--- a/apps/rebreak-native/components/mail/EditMailAccountSheet.tsx
+++ b/apps/rebreak-native/components/mail/EditMailAccountSheet.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { ActivityIndicator, Pressable, Text, TextInput, View } from 'react-native';
+import { ActivityIndicator, TouchableOpacity, Text, TextInput, View } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
import { useMailConnect } from '../../hooks/useMailConnect';
@@ -64,11 +64,11 @@ export function EditMailAccountSheet({ visible, email, onClose, onSuccess }: Pro
borderBottomColor: colors.border,
}}
>
-
+
{t('mail.edit_account_cancel')}
-
+
{t('mail.edit_account_title')}
@@ -125,13 +125,13 @@ export function EditMailAccountSheet({ visible, email, onClose, onSuccess }: Pro
color: colors.text,
}}
/>
- setPasswordVisible((p) => !p)} hitSlop={8}>
+ setPasswordVisible((p) => !p)} hitSlop={8}>
-
+
{(formError ?? connectError) && (
@@ -161,13 +161,11 @@ export function EditMailAccountSheet({ visible, email, onClose, onSuccess }: Pro
)}
- ({
- marginTop: 4,
- opacity: pressed ? 0.85 : 1,
- })}
+ style={{ marginTop: 4 }}
>
)}
-
+
);
diff --git a/apps/rebreak-native/components/mail/MailAccountCard.tsx b/apps/rebreak-native/components/mail/MailAccountCard.tsx
index c6ebbe4..4058674 100644
--- a/apps/rebreak-native/components/mail/MailAccountCard.tsx
+++ b/apps/rebreak-native/components/mail/MailAccountCard.tsx
@@ -4,6 +4,7 @@ import {
LayoutAnimation,
Platform,
Pressable,
+ TouchableOpacity,
Text,
UIManager,
View,
@@ -408,8 +409,9 @@ export function MailAccountCard({
const active = account.scanInterval === opt;
const disabled = plan === 'free' || updating === account.id;
return (
- handleSetInterval(opt)}
style={{
@@ -431,7 +433,7 @@ export function MailAccountCard({
>
{opt}h
-
+
);
})}
@@ -451,7 +453,8 @@ export function MailAccountCard({
)}
- setEditVisible(true)}
style={{ ...ACTION_BTN_BASE, backgroundColor: '#f5f5f5', marginRight: 6 }}
>
@@ -467,8 +470,9 @@ export function MailAccountCard({
>
{t('mail.account_change_password')}
-
-
+ setConfirmVisible(true)}
disabled={disconnecting}
style={{
@@ -496,7 +500,7 @@ export function MailAccountCard({
>
)}
-
+
)}
diff --git a/apps/rebreak-native/components/mail/MailActivityLog.tsx b/apps/rebreak-native/components/mail/MailActivityLog.tsx
index de75ffe..72e3ce7 100644
--- a/apps/rebreak-native/components/mail/MailActivityLog.tsx
+++ b/apps/rebreak-native/components/mail/MailActivityLog.tsx
@@ -2,6 +2,7 @@ import {
LayoutAnimation,
Platform,
Pressable,
+ TouchableOpacity,
Text,
UIManager,
View,
@@ -140,9 +141,9 @@ export function MailActivityLog({ expanded, onToggle }: Props) {
? t('mail.activity_log_more', { count: total - 10 })
: t('mail.activity_log_count', { count: total })}
-
+
-
+
>
)}
diff --git a/apps/rebreak-native/components/mail/MailWeeklyChart.tsx b/apps/rebreak-native/components/mail/MailWeeklyChart.tsx
index a183aff..6ee4783 100644
--- a/apps/rebreak-native/components/mail/MailWeeklyChart.tsx
+++ b/apps/rebreak-native/components/mail/MailWeeklyChart.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { Pressable, Text, View } from 'react-native';
+import { TouchableOpacity, Text, View } from 'react-native';
import Svg, { Rect, Text as SvgText } from 'react-native-svg';
import { useTranslation } from 'react-i18next';
import { useColors } from '../../lib/theme';
@@ -145,10 +145,11 @@ export function MailWeeklyChart({ dailyStats, totalBlocked }: Props) {
}}
>
{dailyStats.map((day, i) => (
- setActiveIdx((prev) => (prev === i ? null : i))}
+ activeOpacity={0.7}
accessibilityLabel={`${day.label}: ${day.count}`}
/>
))}
diff --git a/apps/rebreak-native/components/profile/ApprovedDomainsList.tsx b/apps/rebreak-native/components/profile/ApprovedDomainsList.tsx
index a4eaefd..0cfa7bf 100644
--- a/apps/rebreak-native/components/profile/ApprovedDomainsList.tsx
+++ b/apps/rebreak-native/components/profile/ApprovedDomainsList.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { View, Text, Pressable, LayoutAnimation, Platform, UIManager } from 'react-native';
+import { View, Text, TouchableOpacity, LayoutAnimation, Platform, UIManager } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useColors } from '../../lib/theme';
@@ -28,9 +28,9 @@ export function ApprovedDomainsList({ domains, loading }: Props) {
return (
- ({ opacity: pressed ? 0.7 : 1 })}
+ activeOpacity={0.7}
>
-
+
{expanded ? (
- ({ opacity: pressed ? 0.7 : 1 })}
+ activeOpacity={0.7}
>
)}
-
+
{expanded ? (
- ({ opacity: pressed ? 0.6 : 1 })}
+ activeOpacity={0.6}
>
-
+
@@ -637,9 +637,9 @@ export function DemographicsAccordion({
) : null}
- ({ opacity: pressed ? 0.7 : 1 })}
+ activeOpacity={0.7}
>
-
+
) : null}
@@ -753,9 +753,9 @@ function FieldRow({
function SelectButton({ value, onPress }: { value: string | null; onPress: () => void }) {
const colors = useColors();
return (
- ({ opacity: pressed ? 0.6 : 1 })}
+ activeOpacity={0.6}
>
{/* Value als Chip */}
@@ -782,6 +782,6 @@ function SelectButton({ value, onPress }: { value: string | null; onPress: () =>
{/* Chevron-right am Ende, separat vom Chip */}
-
+
);
}
diff --git a/apps/rebreak-native/components/profile/DigaMissionBanner.tsx b/apps/rebreak-native/components/profile/DigaMissionBanner.tsx
index 1aa68bd..bb647ef 100644
--- a/apps/rebreak-native/components/profile/DigaMissionBanner.tsx
+++ b/apps/rebreak-native/components/profile/DigaMissionBanner.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useColors } from '../../lib/theme';
@@ -60,11 +60,9 @@ export function DigaMissionBanner({ onDismiss, onContribute }: Props) {
- ({
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
>
-
-
+ ({
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
>
-
+
- ({ opacity: pressed ? 0.5 : 1 })}
+ activeOpacity={0.5}
>
-
+
);
diff --git a/apps/rebreak-native/components/profile/ProfileHeader.tsx b/apps/rebreak-native/components/profile/ProfileHeader.tsx
index 26986bb..6a5ff4a 100644
--- a/apps/rebreak-native/components/profile/ProfileHeader.tsx
+++ b/apps/rebreak-native/components/profile/ProfileHeader.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { View, Text, Pressable, Image } from 'react-native';
+import { View, Text, TouchableOpacity, Image } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import Svg, { Path } from 'react-native-svg';
import { useColors } from '../../lib/theme';
@@ -84,12 +84,10 @@ export function ProfileHeader({
{/* Avatar — Pressable in alignSelf:center-Wrapper (Pressable+style-fn ignoriert alignSelf manchmal in RN) */}
- ({
- position: 'relative',
- opacity: pressed ? 0.85 : 1,
- })}
+ activeOpacity={0.85}
+ style={{ position: 'relative' }}
>
-
+
{/* Nickname — ganze Zeile Pressable in alignSelf:center-Wrapper */}
- ({
+ activeOpacity={0.5}
+ style={{
flexDirection: 'row',
alignItems: 'center',
marginTop: 16,
gap: 6,
- opacity: pressed ? 0.5 : 1,
- })}
+ }}
>
{nickname}
-
+
{/* Plan-Tier-Badge direkt unter Nickname — Legend mit sparkles-icon */}
@@ -249,14 +247,11 @@ export function ProfileHeader({
Parent ist KEIN alignItems:center mehr — Hint nimmt natürlich volle Breite (default flex-stretch).
KEIN width:'100%' (Konflikt mit alignSelf:stretch in alignItems:center-Kontext war der Bug). */}
{showDemographicsHint ? (
- ({
- alignSelf: 'center',
- marginTop: 16,
- opacity: pressed ? 0.7 : 1,
- })}
+ activeOpacity={0.7}
+ style={{ alignSelf: 'center', marginTop: 16 }}
>
-
+
) : null}
);
diff --git a/apps/rebreak-native/components/profile/StatsBar.tsx b/apps/rebreak-native/components/profile/StatsBar.tsx
index 0755572..f42a615 100644
--- a/apps/rebreak-native/components/profile/StatsBar.tsx
+++ b/apps/rebreak-native/components/profile/StatsBar.tsx
@@ -1,4 +1,4 @@
-import { View, Text, Pressable } from 'react-native';
+import { View, Text, TouchableOpacity } from 'react-native';
import { useColors } from '../../lib/theme';
type Props = {
@@ -19,9 +19,9 @@ type CardProps = {
function StatPill({ value, label, onPress }: CardProps) {
const colors = useColors();
return (
- ({ opacity: pressed ? 0.6 : 1 })}
+ activeOpacity={0.6}
>
-
+
);
}
diff --git a/apps/rebreak-native/components/urge/Breathing.tsx b/apps/rebreak-native/components/urge/Breathing.tsx
index e7f030e..b6f5575 100644
--- a/apps/rebreak-native/components/urge/Breathing.tsx
+++ b/apps/rebreak-native/components/urge/Breathing.tsx
@@ -1,6 +1,6 @@
// 4-7-8 Atemübung: Card (in-chat) + Drawer (bottom sheet).
import { useEffect, useRef, useState } from 'react';
-import { View, Text, Pressable, Animated, StyleSheet } from 'react-native';
+import { View, Text, TouchableOpacity, Animated, StyleSheet } from 'react-native';
import { BREATH_PHASES, TOTAL_ROUNDS, type BreathState } from '../../lib/sosConstants';
import { useColors } from '../../lib/theme';
@@ -87,9 +87,9 @@ export function BreathingCard({ onDone, onSpeak }: Props) {
4-7-8 Atemübung
3 Runden · beruhigt dein Nervensystem
- { setCountdown(3); setBreathState('countdown'); }}>
+ { setCountdown(3); setBreathState('countdown'); }}>
Starten
-
+
) : breathState === 'countdown' ? (
diff --git a/apps/rebreak-native/components/urge/InlineRatingDrawer.tsx b/apps/rebreak-native/components/urge/InlineRatingDrawer.tsx
index a063a58..5ed522d 100644
--- a/apps/rebreak-native/components/urge/InlineRatingDrawer.tsx
+++ b/apps/rebreak-native/components/urge/InlineRatingDrawer.tsx
@@ -3,6 +3,7 @@ import {
View,
Text,
Pressable,
+ TouchableOpacity,
TextInput,
StyleSheet,
Animated,
@@ -80,7 +81,8 @@ export function InlineRatingDrawer({
Fühlst du dich besser?
- setBetter(true)}
>
@@ -90,8 +92,9 @@ export function InlineRatingDrawer({
color={better === true ? '#fff' : '#16a34a'}
/>
Ja
-
-
+ setBetter(false)}
>
@@ -101,19 +104,19 @@ export function InlineRatingDrawer({
color={better === false ? '#fff' : '#dc2626'}
/>
Nein
-
+
Bewertung
{[1, 2, 3, 4, 5].map((n) => (
- setRating(n)} hitSlop={6}>
+ setRating(n)} hitSlop={6} activeOpacity={0.7}>
-
+
))}
@@ -129,16 +132,17 @@ export function InlineRatingDrawer({
/>
-
+
Abbrechen
-
-
+
{submitting ? 'Sende…' : 'Senden'}
-
+
diff --git a/apps/rebreak-native/components/urge/LlmProviderToggle.tsx b/apps/rebreak-native/components/urge/LlmProviderToggle.tsx
index ff7f968..018a1d6 100644
--- a/apps/rebreak-native/components/urge/LlmProviderToggle.tsx
+++ b/apps/rebreak-native/components/urge/LlmProviderToggle.tsx
@@ -1,4 +1,4 @@
-import { Pressable, Text, View } from 'react-native';
+import { TouchableOpacity, Text, View } from 'react-native';
import { LLM_PROVIDER_LABEL, type LlmProvider, useLlmProvider } from '../../lib/llmProvider';
const PROVIDERS: LlmProvider[] = ['auto', 'openrouter-sonnet', 'openrouter-haiku', 'groq-llama'];
@@ -30,10 +30,11 @@ export function LlmProviderToggle() {
{PROVIDERS.map((p) => {
const active = p === current;
return (
- { void set(p); }}
hitSlop={6}
+ activeOpacity={0.7}
style={{
paddingHorizontal: 10,
paddingVertical: 4,
@@ -52,7 +53,7 @@ export function LlmProviderToggle() {
>
{LLM_PROVIDER_LABEL[p]}
-
+
);
})}
diff --git a/apps/rebreak-native/components/urge/MessageRow.tsx b/apps/rebreak-native/components/urge/MessageRow.tsx
index 421e303..47bbd6b 100644
--- a/apps/rebreak-native/components/urge/MessageRow.tsx
+++ b/apps/rebreak-native/components/urge/MessageRow.tsx
@@ -1,6 +1,6 @@
// Chat-Bubble + Spezial-Cards (Spiele/Überwunden) für den SOS-Chat-Stream
// sowie GameHeader für die aktive Spiel-Session.
-import { View, Text, Pressable, StyleSheet } from 'react-native';
+import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { type GameType, GAME_META, GamePickerGrid } from './UrgeGames';
import { RiveAvatar, type Emotion as LyraEmotion } from '../RiveAvatar';
@@ -57,7 +57,7 @@ export function GameHeader({ game, emotion, onBack }: { game: GameType; emotion:
const meta = GAME_META.find((g) => g.id === game);
return (
-
+
{meta?.id ?? game}
diff --git a/apps/rebreak-native/components/urge/ShareSuccessDrawer.tsx b/apps/rebreak-native/components/urge/ShareSuccessDrawer.tsx
index d470403..5709525 100644
--- a/apps/rebreak-native/components/urge/ShareSuccessDrawer.tsx
+++ b/apps/rebreak-native/components/urge/ShareSuccessDrawer.tsx
@@ -3,6 +3,7 @@ import {
View,
Text,
Pressable,
+ TouchableOpacity,
TextInput,
StyleSheet,
Animated,
@@ -106,19 +107,21 @@ export function ShareSuccessDrawer({
{onRegenerate && (
-
Neu generieren
-
+
)}
-
+
Abbrechen
-
-
+ Teilen
>
)}
-
+
diff --git a/apps/rebreak-native/components/urge/SosFeedbackModal.tsx b/apps/rebreak-native/components/urge/SosFeedbackModal.tsx
index d6032c7..ab389e5 100644
--- a/apps/rebreak-native/components/urge/SosFeedbackModal.tsx
+++ b/apps/rebreak-native/components/urge/SosFeedbackModal.tsx
@@ -1,5 +1,5 @@
import { useState } from 'react';
-import { View, Text, Pressable, TextInput, Modal, StyleSheet, Platform, KeyboardAvoidingView, ScrollView } from 'react-native';
+import { View, Text, Pressable, TouchableOpacity, TextInput, Modal, StyleSheet, Platform, KeyboardAvoidingView, ScrollView } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
import { useColors } from '../../lib/theme';
@@ -51,33 +51,35 @@ export function SosFeedbackModal({
{/* Better Yes/No */}
Fühlst du dich besser?
- setBetter(true)}
>
Ja
-
-
+ setBetter(false)}
>
Nein
-
+
{/* Stars */}
Bewertung
{[1, 2, 3, 4, 5].map((n) => (
- setRating(n)} hitSlop={6}>
+ setRating(n)} hitSlop={6} activeOpacity={0.7}>
-
+
))}
@@ -96,12 +98,12 @@ export function SosFeedbackModal({
{/* Actions */}
-
+
Überspringen
-
-
+
+
Senden
-
+
diff --git a/apps/rebreak-native/components/urge/TtsProviderToggle.tsx b/apps/rebreak-native/components/urge/TtsProviderToggle.tsx
index fb7b4d3..c7047b1 100644
--- a/apps/rebreak-native/components/urge/TtsProviderToggle.tsx
+++ b/apps/rebreak-native/components/urge/TtsProviderToggle.tsx
@@ -1,4 +1,4 @@
-import { Pressable, Text, View } from 'react-native';
+import { TouchableOpacity, Text, View } from 'react-native';
import { TTS_PROVIDER_LABEL, type TtsProvider, useTtsProvider } from '../../lib/ttsProvider';
const PROVIDERS: TtsProvider[] = ['openai', 'gemini', 'elevenlabs', 'cartesia', 'google-cloud'];
@@ -30,10 +30,11 @@ export function TtsProviderToggle() {
{PROVIDERS.map((p) => {
const active = p === current;
return (
- { void set(p); }}
hitSlop={6}
+ activeOpacity={0.7}
style={{
paddingHorizontal: 10,
paddingVertical: 4,
@@ -52,7 +53,7 @@ export function TtsProviderToggle() {
>
{TTS_PROVIDER_LABEL[p]}
-
+
);
})}
diff --git a/apps/rebreak-native/components/urge/UrgeGames.tsx b/apps/rebreak-native/components/urge/UrgeGames.tsx
index 3d29167..fd94598 100644
--- a/apps/rebreak-native/components/urge/UrgeGames.tsx
+++ b/apps/rebreak-native/components/urge/UrgeGames.tsx
@@ -1,5 +1,5 @@
import { useEffect, useMemo, useRef, useState, useCallback } from 'react';
-import { View, Text, Pressable, TouchableWithoutFeedback, Dimensions, PanResponder, Platform } from 'react-native';
+import { View, Text, Pressable, TouchableOpacity, TouchableWithoutFeedback, Dimensions, PanResponder, Platform } from 'react-native';
import Svg, { Defs, Pattern, Path, Rect, Polyline, Circle, Line } from 'react-native-svg';
import { SvgXml } from 'react-native-svg';
import { Ionicons } from '@expo/vector-icons';
@@ -38,13 +38,11 @@ export function GamePickerGrid({ onSelect }: { onSelect: (game: GameType) => voi
return (
{GAME_META.map((game) => (
- onSelect(game.id)}
- style={({ pressed }) => ({
- width: '47%',
- opacity: pressed ? 0.75 : 1,
- })}
+ activeOpacity={0.75}
+ style={{ width: '47%' }}
>
voi
{t(game.descKey)}
-
+
))}
);