Add configurable send behavior
This commit is contained in:
@@ -48,6 +48,7 @@ import { useKeyboardShiftStyle } from "@/hooks/use-keyboard-shift-style";
|
|||||||
import { useKeyboardActionHandler } from "@/hooks/use-keyboard-action-handler";
|
import { useKeyboardActionHandler } from "@/hooks/use-keyboard-action-handler";
|
||||||
import type { KeyboardActionDefinition } from "@/keyboard/keyboard-action-dispatcher";
|
import type { KeyboardActionDefinition } from "@/keyboard/keyboard-action-dispatcher";
|
||||||
import { submitAgentInput } from "@/components/agent-input-submit";
|
import { submitAgentInput } from "@/components/agent-input-submit";
|
||||||
|
import { useAppSettings } from "@/hooks/use-settings";
|
||||||
|
|
||||||
type QueuedMessage = {
|
type QueuedMessage = {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -139,6 +140,8 @@ export function Composer({
|
|||||||
agentDirectoryStatus === "revalidating" ||
|
agentDirectoryStatus === "revalidating" ||
|
||||||
agentDirectoryStatus === "error_after_ready");
|
agentDirectoryStatus === "error_after_ready");
|
||||||
|
|
||||||
|
const { settings: appSettings } = useAppSettings();
|
||||||
|
|
||||||
const agentState = useSessionStore(
|
const agentState = useSessionStore(
|
||||||
useShallow((state) => {
|
useShallow((state) => {
|
||||||
const agent = state.sessions[serverId]?.agents?.get(agentId) ?? null;
|
const agent = state.sessions[serverId]?.agents?.get(agentId) ?? null;
|
||||||
@@ -760,6 +763,7 @@ export function Composer({
|
|||||||
voiceServerId={serverId}
|
voiceServerId={serverId}
|
||||||
voiceAgentId={agentId}
|
voiceAgentId={agentId}
|
||||||
isAgentRunning={isAgentRunning}
|
isAgentRunning={isAgentRunning}
|
||||||
|
defaultSendBehavior={appSettings.sendBehavior}
|
||||||
onQueue={handleQueue}
|
onQueue={handleQueue}
|
||||||
onSubmitLoadingPress={isAgentRunning ? handleCancelAgent : undefined}
|
onSubmitLoadingPress={isAgentRunning ? handleCancelAgent : undefined}
|
||||||
onKeyPress={handleCommandKeyPress}
|
onKeyPress={handleCommandKeyPress}
|
||||||
|
|||||||
@@ -90,6 +90,9 @@ export interface MessageInputProps {
|
|||||||
voiceAgentId?: string;
|
voiceAgentId?: string;
|
||||||
/** When true and there's sendable content, calls onQueue instead of onSubmit */
|
/** When true and there's sendable content, calls onQueue instead of onSubmit */
|
||||||
isAgentRunning?: boolean;
|
isAgentRunning?: boolean;
|
||||||
|
/** Controls what the default send action (Enter, send button, dictation) does
|
||||||
|
* when the agent is running. "interrupt" sends immediately, "queue" queues. */
|
||||||
|
defaultSendBehavior?: "interrupt" | "queue";
|
||||||
/** Callback for queue button when agent is running */
|
/** Callback for queue button when agent is running */
|
||||||
onQueue?: (payload: MessagePayload) => void;
|
onQueue?: (payload: MessagePayload) => void;
|
||||||
/** Optional handler used when submit button is in loading state. */
|
/** Optional handler used when submit button is in loading state. */
|
||||||
@@ -217,6 +220,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
voiceServerId,
|
voiceServerId,
|
||||||
voiceAgentId,
|
voiceAgentId,
|
||||||
isAgentRunning = false,
|
isAgentRunning = false,
|
||||||
|
defaultSendBehavior = "interrupt",
|
||||||
onQueue,
|
onQueue,
|
||||||
onSubmitLoadingPress,
|
onSubmitLoadingPress,
|
||||||
onKeyPress: onKeyPressCallback,
|
onKeyPress: onKeyPressCallback,
|
||||||
@@ -362,11 +366,17 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
|
|
||||||
if (shouldAutoSend) {
|
if (shouldAutoSend) {
|
||||||
const imageAttachments = images.length > 0 ? images : undefined;
|
const imageAttachments = images.length > 0 ? images : undefined;
|
||||||
onSubmit({
|
// Respect send behavior setting: when "queue", dictation queues too.
|
||||||
text: nextValue,
|
if (defaultSendBehavior === "queue" && isAgentRunning && onQueue) {
|
||||||
images: imageAttachments,
|
onQueue({ text: nextValue, images: imageAttachments });
|
||||||
forceSend: isAgentRunning || undefined,
|
onChangeText("");
|
||||||
});
|
} else {
|
||||||
|
onSubmit({
|
||||||
|
text: nextValue,
|
||||||
|
images: imageAttachments,
|
||||||
|
forceSend: isAgentRunning || undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
onChangeText(nextValue);
|
onChangeText(nextValue);
|
||||||
}
|
}
|
||||||
@@ -377,7 +387,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[onChangeText, onSubmit, images, isAgentRunning],
|
[onChangeText, onSubmit, onQueue, images, isAgentRunning, defaultSendBehavior],
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleDictationError = useCallback(
|
const handleDictationError = useCallback(
|
||||||
@@ -588,6 +598,26 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
onHeightChange?.(MIN_INPUT_HEIGHT);
|
onHeightChange?.(MIN_INPUT_HEIGHT);
|
||||||
}, [value, images, onQueue, onChangeText, onHeightChange]);
|
}, [value, images, onQueue, onChangeText, onHeightChange]);
|
||||||
|
|
||||||
|
// Default send action: respects the sendBehavior setting.
|
||||||
|
// When "interrupt" (default), primary action sends immediately (interrupts).
|
||||||
|
// When "queue", primary action queues when agent is running.
|
||||||
|
const handleDefaultSendAction = useCallback(() => {
|
||||||
|
if (defaultSendBehavior === "queue" && isAgentRunning && onQueue) {
|
||||||
|
handleQueueMessage();
|
||||||
|
} else {
|
||||||
|
handleSendMessage();
|
||||||
|
}
|
||||||
|
}, [defaultSendBehavior, isAgentRunning, onQueue, handleQueueMessage, handleSendMessage]);
|
||||||
|
|
||||||
|
// Alternate send action: always the opposite of the default.
|
||||||
|
const handleAlternateSendAction = useCallback(() => {
|
||||||
|
if (defaultSendBehavior === "queue") {
|
||||||
|
handleSendMessage(); // interrupt
|
||||||
|
} else if (onQueue) {
|
||||||
|
handleQueueMessage(); // queue
|
||||||
|
}
|
||||||
|
}, [defaultSendBehavior, handleSendMessage, handleQueueMessage, onQueue]);
|
||||||
|
|
||||||
// Web input height measurement
|
// Web input height measurement
|
||||||
function isTextAreaLike(v: unknown): v is TextAreaHandle {
|
function isTextAreaLike(v: unknown): v is TextAreaHandle {
|
||||||
return typeof v === "object" && v !== null && "scrollHeight" in v;
|
return typeof v === "object" && v !== null && "scrollHeight" in v;
|
||||||
@@ -882,18 +912,18 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
// Shift+Enter: add newline (default behavior, don't intercept)
|
// Shift+Enter: add newline (default behavior, don't intercept)
|
||||||
if (shiftKey) return;
|
if (shiftKey) return;
|
||||||
|
|
||||||
// Cmd+Enter (Mac) or Ctrl+Enter (Windows/Linux): queue when agent is running
|
// Cmd+Enter (Mac) or Ctrl+Enter (Windows/Linux): alternate action
|
||||||
if ((metaKey || ctrlKey) && isAgentRunning && onQueue) {
|
if ((metaKey || ctrlKey) && isAgentRunning && onQueue) {
|
||||||
if (isSubmitDisabled || isSubmitLoading || disabled) return;
|
if (isSubmitDisabled || isSubmitLoading || disabled) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleQueueMessage();
|
handleAlternateSendAction();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enter: send (interrupts agent if running)
|
// Enter: default send action (interrupt or queue, based on setting)
|
||||||
if (isSubmitDisabled || isSubmitLoading || disabled) return;
|
if (isSubmitDisabled || isSubmitLoading || disabled) return;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
handleSendMessage();
|
handleDefaultSendAction();
|
||||||
}
|
}
|
||||||
|
|
||||||
const hasImages = images.length > 0;
|
const hasImages = images.length > 0;
|
||||||
@@ -904,11 +934,14 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
const canPressLoadingButton = isSubmitLoading && typeof onSubmitLoadingPress === "function";
|
const canPressLoadingButton = isSubmitLoading && typeof onSubmitLoadingPress === "function";
|
||||||
const isSendButtonDisabled =
|
const isSendButtonDisabled =
|
||||||
disabled || (!canPressLoadingButton && (isSubmitDisabled || isSubmitLoading));
|
disabled || (!canPressLoadingButton && (isSubmitDisabled || isSubmitLoading));
|
||||||
|
const defaultActionQueues = defaultSendBehavior === "queue" && isAgentRunning;
|
||||||
const submitAccessibilityLabel = canPressLoadingButton
|
const submitAccessibilityLabel = canPressLoadingButton
|
||||||
? "Interrupt agent"
|
? "Interrupt agent"
|
||||||
: isAgentRunning
|
: defaultActionQueues
|
||||||
? "Send and interrupt"
|
? "Queue message"
|
||||||
: "Send message";
|
: isAgentRunning
|
||||||
|
? "Send and interrupt"
|
||||||
|
: "Send message";
|
||||||
|
|
||||||
const handleInputChange = useCallback(
|
const handleInputChange = useCallback(
|
||||||
(nextValue: string) => {
|
(nextValue: string) => {
|
||||||
@@ -1087,10 +1120,10 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{rightContent}
|
{rightContent}
|
||||||
{hasSendableContent && isAgentRunning && onQueue && (
|
{hasSendableContent && isAgentRunning && onQueue && !defaultActionQueues && (
|
||||||
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
||||||
<TooltipTrigger
|
<TooltipTrigger
|
||||||
onPress={handleQueueMessage}
|
onPress={handleAlternateSendAction}
|
||||||
disabled={!isConnected || disabled}
|
disabled={!isConnected || disabled}
|
||||||
accessibilityLabel="Queue message"
|
accessibilityLabel="Queue message"
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
@@ -1115,7 +1148,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
{shouldShowSendButton && (
|
{shouldShowSendButton && (
|
||||||
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
||||||
<TooltipTrigger
|
<TooltipTrigger
|
||||||
onPress={canPressLoadingButton ? onSubmitLoadingPress : handleSendMessage}
|
onPress={canPressLoadingButton ? onSubmitLoadingPress : handleDefaultSendAction}
|
||||||
disabled={isSendButtonDisabled}
|
disabled={isSendButtonDisabled}
|
||||||
accessibilityLabel={showEmptySubmitLabel ? emptySubmitLabel : submitAccessibilityLabel}
|
accessibilityLabel={showEmptySubmitLabel ? emptySubmitLabel : submitAccessibilityLabel}
|
||||||
accessibilityRole="button"
|
accessibilityRole="button"
|
||||||
@@ -1134,7 +1167,13 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(funct
|
|||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent side="top" align="center" offset={8}>
|
<TooltipContent side="top" align="center" offset={8}>
|
||||||
<View style={styles.tooltipRow}>
|
<View style={styles.tooltipRow}>
|
||||||
<Text style={styles.tooltipText}>{showEmptySubmitLabel ? emptySubmitLabel : "Send"}</Text>
|
<Text style={styles.tooltipText}>
|
||||||
|
{showEmptySubmitLabel
|
||||||
|
? emptySubmitLabel
|
||||||
|
: defaultActionQueues
|
||||||
|
? "Queue"
|
||||||
|
: "Send"}
|
||||||
|
</Text>
|
||||||
{sendKeys ? <Shortcut chord={sendKeys} style={styles.tooltipShortcut} /> : null}
|
{sendKeys ? <Shortcut chord={sendKeys} style={styles.tooltipShortcut} /> : null}
|
||||||
</View>
|
</View>
|
||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
|
|||||||
@@ -6,14 +6,18 @@ export const APP_SETTINGS_KEY = "@paseo:app-settings";
|
|||||||
const LEGACY_SETTINGS_KEY = "@paseo:settings";
|
const LEGACY_SETTINGS_KEY = "@paseo:settings";
|
||||||
const APP_SETTINGS_QUERY_KEY = ["app-settings"];
|
const APP_SETTINGS_QUERY_KEY = ["app-settings"];
|
||||||
|
|
||||||
|
export type SendBehavior = "interrupt" | "queue";
|
||||||
|
|
||||||
export interface AppSettings {
|
export interface AppSettings {
|
||||||
theme: "dark" | "light" | "auto";
|
theme: "dark" | "light" | "auto";
|
||||||
manageBuiltInDaemon: boolean;
|
manageBuiltInDaemon: boolean;
|
||||||
|
sendBehavior: SendBehavior;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DEFAULT_APP_SETTINGS: AppSettings = {
|
export const DEFAULT_APP_SETTINGS: AppSettings = {
|
||||||
theme: "auto",
|
theme: "auto",
|
||||||
manageBuiltInDaemon: true,
|
manageBuiltInDaemon: true,
|
||||||
|
sendBehavior: "interrupt",
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface UseAppSettingsReturn {
|
export interface UseAppSettingsReturn {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ import {
|
|||||||
RotateCw,
|
RotateCw,
|
||||||
Trash2,
|
Trash2,
|
||||||
Server,
|
Server,
|
||||||
Palette,
|
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Stethoscope,
|
Stethoscope,
|
||||||
Info,
|
Info,
|
||||||
@@ -24,7 +23,7 @@ import {
|
|||||||
Blocks,
|
Blocks,
|
||||||
Smartphone,
|
Smartphone,
|
||||||
} from "lucide-react-native";
|
} from "lucide-react-native";
|
||||||
import { useAppSettings, type AppSettings } from "@/hooks/use-settings";
|
import { useAppSettings, type AppSettings, type SendBehavior } from "@/hooks/use-settings";
|
||||||
import type { HostProfile, HostConnection } from "@/types/host-connection";
|
import type { HostProfile, HostConnection } from "@/types/host-connection";
|
||||||
import { useHosts, useHostMutations } from "@/runtime/host-runtime";
|
import { useHosts, useHostMutations } from "@/runtime/host-runtime";
|
||||||
import { formatConnectionStatus, getConnectionStatusTone } from "@/utils/daemons";
|
import { formatConnectionStatus, getConnectionStatusTone } from "@/utils/daemons";
|
||||||
@@ -77,7 +76,7 @@ import { StatusBadge } from "@/components/ui/status-badge";
|
|||||||
|
|
||||||
type SettingsSectionId =
|
type SettingsSectionId =
|
||||||
| "hosts"
|
| "hosts"
|
||||||
| "appearance"
|
| "general"
|
||||||
| "shortcuts"
|
| "shortcuts"
|
||||||
| "integrations"
|
| "integrations"
|
||||||
| "providers"
|
| "providers"
|
||||||
@@ -96,7 +95,7 @@ interface SettingsSectionDef {
|
|||||||
function getSettingsSections(context: { isDesktopApp: boolean }): SettingsSectionDef[] {
|
function getSettingsSections(context: { isDesktopApp: boolean }): SettingsSectionDef[] {
|
||||||
const sections: SettingsSectionDef[] = [
|
const sections: SettingsSectionDef[] = [
|
||||||
{ id: "hosts", label: "Hosts", icon: Server },
|
{ id: "hosts", label: "Hosts", icon: Server },
|
||||||
{ id: "appearance", label: "Appearance", icon: Palette },
|
{ id: "general", label: "General", icon: Settings },
|
||||||
{ id: "shortcuts", label: "Shortcuts", icon: Keyboard },
|
{ id: "shortcuts", label: "Shortcuts", icon: Keyboard },
|
||||||
{ id: "permissions", label: "Permissions", icon: Shield },
|
{ id: "permissions", label: "Permissions", icon: Shield },
|
||||||
];
|
];
|
||||||
@@ -386,15 +385,20 @@ function HostsSection(props: HostsSectionProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppearanceSectionProps {
|
interface GeneralSectionProps {
|
||||||
settings: AppSettings;
|
settings: AppSettings;
|
||||||
handleThemeChange: (theme: AppSettings["theme"]) => void;
|
handleThemeChange: (theme: AppSettings["theme"]) => void;
|
||||||
|
handleSendBehaviorChange: (behavior: SendBehavior) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppearanceSection({ settings, handleThemeChange }: AppearanceSectionProps) {
|
function GeneralSection({
|
||||||
|
settings,
|
||||||
|
handleThemeChange,
|
||||||
|
handleSendBehaviorChange,
|
||||||
|
}: GeneralSectionProps) {
|
||||||
return (
|
return (
|
||||||
<View style={settingsStyles.section}>
|
<View style={settingsStyles.section}>
|
||||||
<Text style={settingsStyles.sectionTitle}>Appearance</Text>
|
<Text style={settingsStyles.sectionTitle}>General</Text>
|
||||||
<View style={[settingsStyles.card, styles.audioCard]}>
|
<View style={[settingsStyles.card, styles.audioCard]}>
|
||||||
<View style={styles.audioRow}>
|
<View style={styles.audioRow}>
|
||||||
<View style={styles.audioRowContent}>
|
<View style={styles.audioRowContent}>
|
||||||
@@ -424,6 +428,23 @@ function AppearanceSection({ settings, handleThemeChange }: AppearanceSectionPro
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
|
<View style={styles.audioRow}>
|
||||||
|
<View style={styles.audioRowContent}>
|
||||||
|
<Text style={styles.audioRowTitle}>Default send</Text>
|
||||||
|
<Text style={styles.audioRowSubtitle}>
|
||||||
|
What happens when you press Enter while the agent is running
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
<SegmentedControl
|
||||||
|
size="sm"
|
||||||
|
value={settings.sendBehavior}
|
||||||
|
onValueChange={handleSendBehaviorChange}
|
||||||
|
options={[
|
||||||
|
{ value: "interrupt", label: "Interrupt" },
|
||||||
|
{ value: "queue", label: "Queue" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
);
|
);
|
||||||
@@ -613,7 +634,7 @@ function AboutSection({ appVersionText, isDesktopApp }: AboutSectionProps) {
|
|||||||
interface SettingsSectionContentProps {
|
interface SettingsSectionContentProps {
|
||||||
sectionId: SettingsSectionId;
|
sectionId: SettingsSectionId;
|
||||||
hostsProps: HostsSectionProps;
|
hostsProps: HostsSectionProps;
|
||||||
appearanceProps: AppearanceSectionProps;
|
generalProps: GeneralSectionProps;
|
||||||
providersProps: ProvidersSectionProps;
|
providersProps: ProvidersSectionProps;
|
||||||
diagnosticsProps: DiagnosticsSectionProps;
|
diagnosticsProps: DiagnosticsSectionProps;
|
||||||
aboutProps: AboutSectionProps;
|
aboutProps: AboutSectionProps;
|
||||||
@@ -625,7 +646,7 @@ interface SettingsSectionContentProps {
|
|||||||
function SettingsSectionContent({
|
function SettingsSectionContent({
|
||||||
sectionId,
|
sectionId,
|
||||||
hostsProps,
|
hostsProps,
|
||||||
appearanceProps,
|
generalProps,
|
||||||
providersProps,
|
providersProps,
|
||||||
diagnosticsProps,
|
diagnosticsProps,
|
||||||
aboutProps,
|
aboutProps,
|
||||||
@@ -636,8 +657,8 @@ function SettingsSectionContent({
|
|||||||
switch (sectionId) {
|
switch (sectionId) {
|
||||||
case "hosts":
|
case "hosts":
|
||||||
return <HostsSection {...hostsProps} />;
|
return <HostsSection {...hostsProps} />;
|
||||||
case "appearance":
|
case "general":
|
||||||
return <AppearanceSection {...appearanceProps} />;
|
return <GeneralSection {...generalProps} />;
|
||||||
case "shortcuts":
|
case "shortcuts":
|
||||||
return <KeyboardShortcutsSection />;
|
return <KeyboardShortcutsSection />;
|
||||||
case "providers":
|
case "providers":
|
||||||
@@ -1002,6 +1023,13 @@ export default function SettingsScreen() {
|
|||||||
[updateSettings],
|
[updateSettings],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleSendBehaviorChange = useCallback(
|
||||||
|
(behavior: SendBehavior) => {
|
||||||
|
void updateSettings({ sendBehavior: behavior });
|
||||||
|
},
|
||||||
|
[updateSettings],
|
||||||
|
);
|
||||||
|
|
||||||
const handlePlaybackTest = useCallback(async () => {
|
const handlePlaybackTest = useCallback(async () => {
|
||||||
if (!voiceAudioEngine || isPlaybackTestRunning) {
|
if (!voiceAudioEngine || isPlaybackTestRunning) {
|
||||||
return;
|
return;
|
||||||
@@ -1068,9 +1096,10 @@ export default function SettingsScreen() {
|
|||||||
isMountedRef,
|
isMountedRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
const appearanceProps: AppearanceSectionProps = {
|
const generalProps: GeneralSectionProps = {
|
||||||
settings,
|
settings,
|
||||||
handleThemeChange,
|
handleThemeChange,
|
||||||
|
handleSendBehaviorChange,
|
||||||
};
|
};
|
||||||
|
|
||||||
const providersProps: ProvidersSectionProps = {
|
const providersProps: ProvidersSectionProps = {
|
||||||
@@ -1091,7 +1120,7 @@ export default function SettingsScreen() {
|
|||||||
|
|
||||||
const sectionContentProps: Omit<SettingsSectionContentProps, "sectionId"> = {
|
const sectionContentProps: Omit<SettingsSectionContentProps, "sectionId"> = {
|
||||||
hostsProps,
|
hostsProps,
|
||||||
appearanceProps,
|
generalProps,
|
||||||
providersProps,
|
providersProps,
|
||||||
diagnosticsProps,
|
diagnosticsProps,
|
||||||
aboutProps,
|
aboutProps,
|
||||||
@@ -1900,6 +1929,11 @@ const styles = StyleSheet.create((theme) => ({
|
|||||||
color: theme.colors.foreground,
|
color: theme.colors.foreground,
|
||||||
fontSize: theme.fontSize.base,
|
fontSize: theme.fontSize.base,
|
||||||
},
|
},
|
||||||
|
audioRowSubtitle: {
|
||||||
|
color: theme.colors.mutedForeground,
|
||||||
|
fontSize: theme.fontSize.sm,
|
||||||
|
marginTop: theme.spacing[1],
|
||||||
|
},
|
||||||
providerActions: {
|
providerActions: {
|
||||||
flexDirection: "row",
|
flexDirection: "row",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
|
|||||||
Reference in New Issue
Block a user