diff --git a/apps/rebreak-native/app/(app)/mail.tsx b/apps/rebreak-native/app/(app)/mail.tsx
index 1c8eab4..9a29a52 100644
--- a/apps/rebreak-native/app/(app)/mail.tsx
+++ b/apps/rebreak-native/app/(app)/mail.tsx
@@ -5,6 +5,7 @@ import {
Pressable,
ScrollView,
Text,
+ TouchableOpacity,
View,
} from 'react-native';
import { useBottomTabBarHeight } from 'react-native-bottom-tabs';
@@ -173,62 +174,59 @@ export default function MailScreen() {
)}
- {/* Section header with prominent + button */}
-
-
-
- {t('mail.section_accounts')}
-
-
- {maxAccounts === Infinity
- ? t('mail.section_accounts_count_unlimited', { used: accounts.length })
- : t('mail.section_accounts_count', {
- used: accounts.length,
- max: maxAccounts,
- })}
-
-
-
- 0 && (
+
-
+
+ {t('mail.section_accounts')}
+
+
+ {maxAccounts === Infinity
+ ? t('mail.section_accounts_count_unlimited', { used: accounts.length })
+ : t('mail.section_accounts_count', {
+ used: accounts.length,
+ max: maxAccounts,
+ })}
+
+
+
+
{t('mail.add_account')}
-
-
-
+
+
+ )}
{/* Account cards or empty */}
{accounts.length === 0 ? (
diff --git a/apps/rebreak-native/components/SheetFieldStack.tsx b/apps/rebreak-native/components/SheetFieldStack.tsx
index 35febfb..5185efa 100644
--- a/apps/rebreak-native/components/SheetFieldStack.tsx
+++ b/apps/rebreak-native/components/SheetFieldStack.tsx
@@ -27,6 +27,13 @@ export type SheetField = {
type Props = {
fields: SheetField[];
+ /**
+ * Immer sichtbarer Bereich über Chips + aktivem Input — für Hinweise, die der User
+ * sehen soll BEVOR er tippt. Wird in einer eigenen ScrollView mit `flexShrink:1`
+ * gerendert, sodass er bei kleinem verfügbaren Platz (Tastatur offen) schrumpft,
+ * der Eingabebereich aber nie weggedrückt wird.
+ */
+ intro?: ReactNode;
/** Rendert sich nach dem letzten Feld — sichtbar sobald alle Felder ausgefüllt sind. */
children?: ReactNode;
onComplete?: () => void;
@@ -41,7 +48,7 @@ type Props = {
*
* Wird als `children` von `` benutzt.
*/
-export function SheetFieldStack({ fields, children, onComplete }: Props) {
+export function SheetFieldStack({ fields, intro, children, onComplete }: Props) {
const colors = useColors();
const [activeIndex, setActiveIndex] = useState(0);
const [fieldErrors, setFieldErrors] = useState>({});
@@ -84,142 +91,157 @@ export function SheetFieldStack({ fields, children, onComplete }: Props) {
const isLast = activeIndex === fields.length - 1;
return (
-
- {/* Abgeschlossene Felder als Chips */}
- {fields.slice(0, activeIndex).map((field, index) => (
- goToField(index)}
- style={{
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: colors.surface,
- borderWidth: 1,
- borderColor: colors.border,
- borderRadius: 12,
- paddingHorizontal: 14,
- paddingVertical: 10,
- gap: 10,
- }}
+
+ {/* Intro: immer sichtbar, schrumpft bei wenig Platz (Tastatur offen) */}
+ {intro != null && (
+
-
-
- {field.label}
-
-
- {field.secureTextEntry ? '••••••••' : field.value}
-
-
-
-
- ))}
+ {intro}
+
+ )}
- {/* Aktives Feld */}
- {!allDone && (
-
-
+ {/* Abgeschlossene Felder als Chips */}
+ {fields.slice(0, activeIndex).map((field, index) => (
+ goToField(index)}
style={{
- fontSize: 12,
- fontFamily: 'Nunito_600SemiBold',
- color: colors.textMuted,
- marginBottom: 6,
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: colors.surface,
+ borderWidth: 1,
+ borderColor: colors.border,
+ borderRadius: 12,
+ paddingHorizontal: 14,
+ paddingVertical: 10,
+ gap: 10,
}}
>
- {fields[activeIndex].label}
-
-
-
- {
- fields[activeIndex].onChangeText(v);
- if (fieldErrors[fields[activeIndex].key]) {
- setFieldErrors((prev) => {
- const next = { ...prev };
- delete next[fields[activeIndex].key];
- return next;
- });
- }
- }}
- placeholder={fields[activeIndex].placeholder}
- placeholderTextColor={colors.textMuted}
- keyboardType={fields[activeIndex].keyboardType ?? 'default'}
- secureTextEntry={fields[activeIndex].secureTextEntry}
- autoCapitalize={fields[activeIndex].autoCapitalize ?? 'sentences'}
- autoCorrect={fields[activeIndex].autoCorrect ?? true}
- returnKeyType={isLast ? 'done' : 'next'}
- onSubmitEditing={advanceOrFinish}
- blurOnSubmit={false}
- style={{
- flex: 1,
- paddingVertical: 12,
- fontSize: 15,
- fontFamily: 'Nunito_400Regular',
- color: colors.text,
- }}
- />
- {fields[activeIndex].suffix}
+
+
+ {field.label}
+
+
+ {field.secureTextEntry ? '••••••••' : field.value}
+
+
+
+ ))}
-
-
-
-
- {fieldErrors[fields[activeIndex].key] && (
+ {/* Aktives Feld */}
+ {!allDone && (
+
- {fieldErrors[fields[activeIndex].key]}
+ {fields[activeIndex].label}
- )}
-
- )}
+
+
+ {
+ fields[activeIndex].onChangeText(v);
+ if (fieldErrors[fields[activeIndex].key]) {
+ setFieldErrors((prev) => {
+ const next = { ...prev };
+ delete next[fields[activeIndex].key];
+ return next;
+ });
+ }
+ }}
+ placeholder={fields[activeIndex].placeholder}
+ placeholderTextColor={colors.textMuted}
+ keyboardType={fields[activeIndex].keyboardType ?? 'default'}
+ secureTextEntry={fields[activeIndex].secureTextEntry}
+ autoCapitalize={fields[activeIndex].autoCapitalize ?? 'sentences'}
+ autoCorrect={fields[activeIndex].autoCorrect ?? true}
+ returnKeyType={isLast ? 'done' : 'next'}
+ onSubmitEditing={advanceOrFinish}
+ blurOnSubmit={false}
+ style={{
+ flex: 1,
+ paddingVertical: 12,
+ fontSize: 15,
+ fontFamily: 'Nunito_400Regular',
+ color: colors.text,
+ }}
+ />
+ {fields[activeIndex].suffix}
+
- {/* Rest des Formulars — sichtbar wenn alle Felder durch */}
- {allDone && children}
-
+
+
+
+
+ {fieldErrors[fields[activeIndex].key] && (
+
+ {fieldErrors[fields[activeIndex].key]}
+
+ )}
+
+ )}
+
+ {/* Rest des Formulars — sichtbar wenn alle Felder durch */}
+ {allDone && children}
+
+
);
}
diff --git a/apps/rebreak-native/components/mail/ConnectMailSheet.tsx b/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
index e746531..40e17b5 100644
--- a/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
+++ b/apps/rebreak-native/components/mail/ConnectMailSheet.tsx
@@ -189,92 +189,93 @@ export function ConnectMailSheet({ visible, onClose, onSuccess }: Props) {
),
},
]}
- onComplete={() => setFieldsComplete(true)}
- >
- {/* App-Password-Guide — über den Datenschutz-Hinweis */}
- {selectedProvider && selectedProvider.id !== 'other' && (
-
-
-
-
- {t('mail.app_password_required_title')}
-
-
+ {/* App-Password-Guide — provider-spezifisch, nicht für 'other' */}
+ {selectedProvider && selectedProvider.id !== 'other' && (
+
- {t(selectedProvider.guideKey)}
-
- {selectedProvider.guideUrl.length > 0 && (
- Linking.openURL(selectedProvider.guideUrl)}
- >
+
+
+
+ {t('mail.app_password_required_title')}
+
- {t('mail.app_password_open_link')} →
+ {t(selectedProvider.guideKey)}
-
- )}
+ {selectedProvider.guideUrl.length > 0 && (
+ Linking.openURL(selectedProvider.guideUrl)}
+ >
+
+ {t('mail.app_password_open_link')} →
+
+
+ )}
+
+
+ )}
+
+ {/* Datenschutz-Zusicherung — immer sichtbar */}
+
+
+
+ {t('mail.form_privacy_note')}
+
- )}
-
- {/* Datenschutz-Hinweis */}
-
-
-
- {t('mail.form_privacy_note')}
-
-
-
+ }
+ onComplete={() => setFieldsComplete(true)}
+ >
{/* Fehler */}
{(formError ?? (connectError ? t(humanizeMailError(connectError)) : null)) && (
{/* CTA */}
- ({
- opacity: pressed ? 0.85 : 1,
- alignSelf: 'stretch',
- })}
+ activeOpacity={0.85}
+ style={{ alignSelf: 'stretch' }}
>
-
+
);
}