1import { ScreenScrollView as ScrollView } from "../../components/ScreenScrollView";
2import { useAtomSet, useAtomValue } from "@effect/atom-react";
3import { useNavigation } from "@react-navigation/native";
4import { AsyncResult } from "effect/reactivity";
5import { Platform, View } from "react-native";
6import { useSafeAreaInsets } from "react-native-safe-area-context";
7
8import { AndroidScreenHeader } from "../../components/AndroidScreenHeader";
9import { AppText as Text } from "../../components/AppText";
10import { NativeStackScreenOptions } from "../../native/StackHeader";
11import {
12 DEFAULT_COMPOSER_ENTER_BEHAVIOR,
13 type ComposerEnterBehavior,
14} from "../../lib/composerEnterBehavior";
15import { mobilePreferencesAtom, updateMobilePreferencesAtom } from "../../state/preferences";
16import { SettingsChoiceRow } from "./components/SettingsChoiceRow";
17import { SettingsSection } from "./components/SettingsSection";
18
19const ENTER_BEHAVIOR_OPTIONS: ReadonlyArray<{
20 readonly behavior: ComposerEnterBehavior;
21 readonly label: string;
22 readonly description: string;
23}> = [
24 {
25 behavior: "send",
26 label: "Send message",
27 description: "Return sends the message. Shift-Return inserts a new line.",
28 },
29 {
30 behavior: "newline",
31 label: "Insert new line",
32 description: "Return inserts a new line. Command-Return sends the message.",
33 },
34];
35
36export function SettingsKeyboardRouteScreen() {
37 const navigation = useNavigation();
38 const insets = useSafeAreaInsets();
39 const preferencesResult = useAtomValue(mobilePreferencesAtom);
40 const savePreferences = useAtomSet(updateMobilePreferencesAtom);
41 const preferencesReady = AsyncResult.isSuccess(preferencesResult) && !preferencesResult.waiting;
42 const selectedBehavior = AsyncResult.isSuccess(preferencesResult)
43 ? (preferencesResult.value.composerEnterBehavior ?? DEFAULT_COMPOSER_ENTER_BEHAVIOR)
44 : null;
45
46 return (
47 <View collapsable={false} className="flex-1 bg-sheet">
48 {Platform.OS === "android" ? (
49 <>
50 <NativeStackScreenOptions options={{ headerShown: false }} />
51 <AndroidScreenHeader title="Keyboard" onBack={() => navigation.goBack()} />
52 </>
53 ) : null}
54 <ScrollView
55 contentInsetAdjustmentBehavior="automatic"
56 showsVerticalScrollIndicator={false}
57 className="flex-1"
58 contentContainerClassName="gap-3 px-5 pt-4"
59 contentContainerStyle={{ paddingBottom: Math.max(insets.bottom, 18) + 18 }}
60 >
61 <SettingsSection title="Return key">
62 {ENTER_BEHAVIOR_OPTIONS.map((option, index) => (
63 <SettingsChoiceRow
64 key={option.behavior}
65 label={option.label}
66 description={option.description}
67 selected={selectedBehavior === option.behavior}
68 separated={index > 0}
69 disabled={!preferencesReady}
70 onPress={() => savePreferences({ composerEnterBehavior: option.behavior })}
71 />
72 ))}
73 </SettingsSection>
74 <Text className="px-2 text-sm text-foreground-muted">
75 Applies to the composer when a hardware keyboard is connected.
76 </Text>
77 </ScrollView>
78 </View>
79 );
80}