- 创建药品通知服务模块,统一管理药品提醒通知的调度和取消 - 新增独立的通知设置页面,支持总开关和药品提醒开关分离控制 - 重构药品详情页面,移除频率编辑功能到独立页面 - 优化药品添加流程,支持拍照和相册选择图片 - 改进通知权限检查和错误处理机制 - 更新用户偏好设置,添加药品提醒开关配置
680 lines
20 KiB
TypeScript
680 lines
20 KiB
TypeScript
import { ThemedText } from '@/components/ThemedText';
|
|
import { HeaderBar } from '@/components/ui/HeaderBar';
|
|
import { Colors } from '@/constants/Colors';
|
|
import { TIMES_PER_DAY_OPTIONS } from '@/constants/Medication';
|
|
import { useAppDispatch } from '@/hooks/redux';
|
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
import { medicationNotificationService } from '@/services/medicationNotifications';
|
|
import { updateMedicationAction } from '@/store/medicationsSlice';
|
|
import type { RepeatPattern } from '@/types/medication';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import DateTimePicker from '@react-native-community/datetimepicker';
|
|
import { Picker } from '@react-native-picker/picker';
|
|
import dayjs from 'dayjs';
|
|
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import {
|
|
ActivityIndicator,
|
|
Alert,
|
|
Modal,
|
|
Platform,
|
|
Pressable,
|
|
ScrollView,
|
|
StyleSheet,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
|
const DEFAULT_TIME_PRESETS = ['08:00', '12:00', '18:00', '22:00'];
|
|
|
|
// 辅助函数:从时间字符串创建 Date 对象
|
|
const createDateFromTime = (time: string) => {
|
|
try {
|
|
if (!time || typeof time !== 'string') {
|
|
console.warn('[MEDICATION] Invalid time string provided:', time);
|
|
return new Date();
|
|
}
|
|
|
|
const parts = time.split(':');
|
|
if (parts.length !== 2) {
|
|
console.warn('[MEDICATION] Invalid time format:', time);
|
|
return new Date();
|
|
}
|
|
|
|
const hour = parseInt(parts[0], 10);
|
|
const minute = parseInt(parts[1], 10);
|
|
|
|
if (isNaN(hour) || isNaN(minute) || hour < 0 || hour > 23 || minute < 0 || minute > 59) {
|
|
console.warn('[MEDICATION] Invalid time values:', { hour, minute });
|
|
return new Date();
|
|
}
|
|
|
|
const next = new Date();
|
|
next.setHours(hour, minute, 0, 0);
|
|
|
|
if (isNaN(next.getTime())) {
|
|
console.error('[MEDICATION] Failed to create valid date');
|
|
return new Date();
|
|
}
|
|
|
|
return next;
|
|
} catch (error) {
|
|
console.error('[MEDICATION] Error in createDateFromTime:', error);
|
|
return new Date();
|
|
}
|
|
};
|
|
|
|
// 辅助函数:格式化时间
|
|
const formatTime = (date: Date) => dayjs(date).format('HH:mm');
|
|
|
|
// 辅助函数:获取默认时间
|
|
const getDefaultTimeByIndex = (index: number) => {
|
|
return DEFAULT_TIME_PRESETS[index % DEFAULT_TIME_PRESETS.length];
|
|
};
|
|
|
|
export default function EditMedicationFrequencyScreen() {
|
|
const params = useLocalSearchParams<{
|
|
medicationId?: string;
|
|
medicationName?: string;
|
|
repeatPattern?: RepeatPattern;
|
|
timesPerDay?: string;
|
|
medicationTimes?: string;
|
|
}>();
|
|
|
|
const medicationId = Array.isArray(params.medicationId) ? params.medicationId[0] : params.medicationId;
|
|
const medicationName = Array.isArray(params.medicationName) ? params.medicationName[0] : params.medicationName;
|
|
const initialRepeatPattern = (Array.isArray(params.repeatPattern) ? params.repeatPattern[0] : params.repeatPattern) as RepeatPattern || 'daily';
|
|
const initialTimesPerDay = parseInt(Array.isArray(params.timesPerDay) ? params.timesPerDay[0] : params.timesPerDay || '1', 10);
|
|
const initialTimes = params.medicationTimes
|
|
? (Array.isArray(params.medicationTimes) ? params.medicationTimes[0] : params.medicationTimes).split(',')
|
|
: ['08:00'];
|
|
|
|
const dispatch = useAppDispatch();
|
|
const router = useRouter();
|
|
const scheme = (useColorScheme() ?? 'light') as keyof typeof Colors;
|
|
const colors = Colors[scheme];
|
|
const insets = useSafeAreaInsets();
|
|
|
|
const [repeatPattern, setRepeatPattern] = useState<RepeatPattern>(initialRepeatPattern);
|
|
const [timesPerDay, setTimesPerDay] = useState(initialTimesPerDay);
|
|
const [medicationTimes, setMedicationTimes] = useState<string[]>(initialTimes);
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
// 时间选择器相关状态
|
|
const [timePickerVisible, setTimePickerVisible] = useState(false);
|
|
const [timePickerDate, setTimePickerDate] = useState<Date>(new Date());
|
|
const [editingTimeIndex, setEditingTimeIndex] = useState<number | null>(null);
|
|
|
|
// 根据 timesPerDay 动态调整 medicationTimes
|
|
useEffect(() => {
|
|
setMedicationTimes((prev) => {
|
|
if (timesPerDay > prev.length) {
|
|
const next = [...prev];
|
|
while (next.length < timesPerDay) {
|
|
next.push(getDefaultTimeByIndex(next.length));
|
|
}
|
|
return next;
|
|
}
|
|
if (timesPerDay < prev.length) {
|
|
return prev.slice(0, timesPerDay);
|
|
}
|
|
return prev;
|
|
});
|
|
}, [timesPerDay]);
|
|
|
|
// 打开时间选择器
|
|
const openTimePicker = useCallback(
|
|
(index?: number) => {
|
|
try {
|
|
if (typeof index === 'number') {
|
|
if (index >= 0 && index < medicationTimes.length) {
|
|
setEditingTimeIndex(index);
|
|
setTimePickerDate(createDateFromTime(medicationTimes[index]));
|
|
} else {
|
|
console.error('[MEDICATION] Invalid time index:', index);
|
|
return;
|
|
}
|
|
} else {
|
|
setEditingTimeIndex(null);
|
|
setTimePickerDate(createDateFromTime(getDefaultTimeByIndex(medicationTimes.length)));
|
|
}
|
|
setTimePickerVisible(true);
|
|
} catch (error) {
|
|
console.error('[MEDICATION] Error in openTimePicker:', error);
|
|
}
|
|
},
|
|
[medicationTimes]
|
|
);
|
|
|
|
// 确认时间选择
|
|
const confirmTime = useCallback(
|
|
(date: Date) => {
|
|
try {
|
|
if (!date || isNaN(date.getTime())) {
|
|
console.error('[MEDICATION] Invalid date provided to confirmTime');
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
return;
|
|
}
|
|
|
|
const nextValue = formatTime(date);
|
|
setMedicationTimes((prev) => {
|
|
if (editingTimeIndex == null) {
|
|
return [...prev, nextValue];
|
|
}
|
|
return prev.map((time, idx) => (idx === editingTimeIndex ? nextValue : time));
|
|
});
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
} catch (error) {
|
|
console.error('[MEDICATION] Error in confirmTime:', error);
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
}
|
|
},
|
|
[editingTimeIndex]
|
|
);
|
|
|
|
// 删除时间
|
|
const removeTime = useCallback((index: number) => {
|
|
setMedicationTimes((prev) => {
|
|
if (prev.length === 1) {
|
|
return prev; // 至少保留一个时间
|
|
}
|
|
return prev.filter((_, idx) => idx !== index);
|
|
});
|
|
// 同时更新 timesPerDay
|
|
setTimesPerDay((prev) => Math.max(1, prev - 1));
|
|
}, []);
|
|
|
|
// 添加时间
|
|
const addTime = useCallback(() => {
|
|
openTimePicker();
|
|
// 同时更新 timesPerDay
|
|
setTimesPerDay((prev) => prev + 1);
|
|
}, [openTimePicker]);
|
|
|
|
// 保存修改
|
|
const handleSave = useCallback(async () => {
|
|
if (!medicationId || saving) return;
|
|
|
|
setSaving(true);
|
|
try {
|
|
const updated = await dispatch(
|
|
updateMedicationAction({
|
|
id: medicationId,
|
|
repeatPattern,
|
|
timesPerDay,
|
|
medicationTimes,
|
|
})
|
|
).unwrap();
|
|
|
|
// 重新安排药品通知
|
|
try {
|
|
await medicationNotificationService.scheduleMedicationNotifications(updated);
|
|
} catch (error) {
|
|
console.error('[MEDICATION] 安排药品通知失败:', error);
|
|
}
|
|
|
|
router.back();
|
|
} catch (err) {
|
|
console.error('更新频率失败', err);
|
|
Alert.alert('更新失败', '更新服药频率时出现问题,请稍后重试。');
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
}, [dispatch, medicationId, medicationTimes, repeatPattern, router, saving, timesPerDay]);
|
|
|
|
const frequencyLabel = useMemo(() => {
|
|
switch (repeatPattern) {
|
|
case 'daily':
|
|
return `每日 ${timesPerDay} 次`;
|
|
case 'weekly':
|
|
return `每周 ${timesPerDay} 次`;
|
|
default:
|
|
return `自定义 · ${timesPerDay} 次/日`;
|
|
}
|
|
}, [repeatPattern, timesPerDay]);
|
|
|
|
if (!medicationId) {
|
|
return (
|
|
<View style={[styles.container, { backgroundColor: colors.pageBackgroundEmphasis }]}>
|
|
<HeaderBar title="编辑服药频率" variant="minimal" />
|
|
<View style={styles.centered}>
|
|
<ThemedText style={styles.emptyText}>缺少必要参数</ThemedText>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View style={[styles.container, { backgroundColor: colors.pageBackgroundEmphasis }]}>
|
|
<HeaderBar
|
|
title="编辑服药频率"
|
|
variant="minimal"
|
|
transparent
|
|
/>
|
|
|
|
<ScrollView
|
|
contentContainerStyle={[
|
|
styles.content,
|
|
{
|
|
paddingTop: insets.top + 72,
|
|
paddingBottom: Math.max(insets.bottom, 16) + 120,
|
|
},
|
|
]}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
{/* 药品名称提示 */}
|
|
{medicationName && (
|
|
<View style={[styles.medicationNameCard, { backgroundColor: colors.surface }]}>
|
|
<Ionicons name="medical" size={20} color={colors.primary} />
|
|
<ThemedText style={[styles.medicationNameText, { color: colors.text }]}>
|
|
{medicationName}
|
|
</ThemedText>
|
|
</View>
|
|
)}
|
|
|
|
{/* 频率选择 */}
|
|
<View style={styles.section}>
|
|
<ThemedText style={[styles.sectionTitle, { color: colors.text }]}>
|
|
服药频率
|
|
</ThemedText>
|
|
<ThemedText style={[styles.sectionDescription, { color: colors.textSecondary }]}>
|
|
设置每日服药次数
|
|
</ThemedText>
|
|
|
|
<View style={styles.pickerRow}>
|
|
<View style={styles.pickerColumn}>
|
|
<ThemedText style={[styles.pickerLabel, { color: colors.textSecondary }]}>
|
|
重复模式
|
|
</ThemedText>
|
|
<Picker
|
|
selectedValue={repeatPattern}
|
|
onValueChange={(value) => setRepeatPattern(value as RepeatPattern)}
|
|
itemStyle={styles.pickerItem}
|
|
style={styles.picker}
|
|
>
|
|
<Picker.Item label="每日" value="daily" />
|
|
{/* <Picker.Item label="每周" value="weekly" />
|
|
<Picker.Item label="自定义" value="custom" /> */}
|
|
</Picker>
|
|
</View>
|
|
<View style={styles.pickerColumn}>
|
|
<ThemedText style={[styles.pickerLabel, { color: colors.textSecondary }]}>
|
|
每日次数
|
|
</ThemedText>
|
|
<Picker
|
|
selectedValue={timesPerDay}
|
|
onValueChange={(value) => setTimesPerDay(Number(value))}
|
|
itemStyle={styles.pickerItem}
|
|
style={styles.picker}
|
|
>
|
|
{TIMES_PER_DAY_OPTIONS.map((times) => (
|
|
<Picker.Item
|
|
key={times}
|
|
label={`${times} 次`}
|
|
value={times}
|
|
/>
|
|
))}
|
|
</Picker>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={[styles.frequencySummary, { backgroundColor: colors.surface }]}>
|
|
<Ionicons name="repeat" size={18} color={colors.primary} />
|
|
<ThemedText style={[styles.frequencySummaryText, { color: colors.text }]}>
|
|
{frequencyLabel}
|
|
</ThemedText>
|
|
</View>
|
|
</View>
|
|
|
|
{/* 提醒时间列表 */}
|
|
<View style={styles.section}>
|
|
<ThemedText style={[styles.sectionTitle, { color: colors.text }]}>
|
|
每日提醒时间
|
|
</ThemedText>
|
|
<ThemedText style={[styles.sectionDescription, { color: colors.textSecondary }]}>
|
|
添加并管理每天的提醒时间
|
|
</ThemedText>
|
|
|
|
<View style={styles.timeList}>
|
|
{medicationTimes.map((time, index) => (
|
|
<View
|
|
key={`${time}-${index}`}
|
|
style={[
|
|
styles.timeItem,
|
|
{
|
|
borderColor: `${colors.border}80`,
|
|
backgroundColor: colors.surface,
|
|
},
|
|
]}
|
|
>
|
|
<TouchableOpacity style={styles.timeValue} onPress={() => openTimePicker(index)}>
|
|
<Ionicons name="time" size={20} color={colors.primary} />
|
|
<ThemedText style={[styles.timeText, { color: colors.text }]}>{time}</ThemedText>
|
|
</TouchableOpacity>
|
|
<Pressable
|
|
onPress={() => removeTime(index)}
|
|
disabled={medicationTimes.length === 1}
|
|
hitSlop={12}
|
|
>
|
|
<Ionicons
|
|
name="close-circle"
|
|
size={20}
|
|
color={medicationTimes.length === 1 ? `${colors.border}80` : colors.textSecondary}
|
|
/>
|
|
</Pressable>
|
|
</View>
|
|
))}
|
|
|
|
<TouchableOpacity
|
|
style={[styles.addTimeButton, { borderColor: colors.primary }]}
|
|
onPress={addTime}
|
|
>
|
|
<Ionicons name="add" size={18} color={colors.primary} />
|
|
<ThemedText style={[styles.addTimeLabel, { color: colors.primary }]}>
|
|
添加时间
|
|
</ThemedText>
|
|
</TouchableOpacity>
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
|
|
{/* 底部保存按钮 */}
|
|
<View
|
|
style={[
|
|
styles.footerBar,
|
|
{
|
|
paddingBottom: Math.max(insets.bottom, 18),
|
|
backgroundColor: colors.pageBackgroundEmphasis,
|
|
},
|
|
]}
|
|
>
|
|
<TouchableOpacity
|
|
activeOpacity={0.9}
|
|
onPress={handleSave}
|
|
disabled={saving}
|
|
>
|
|
{isLiquidGlassAvailable() ? (
|
|
<GlassView
|
|
style={styles.saveButton}
|
|
glassEffectStyle="regular"
|
|
tintColor={`rgba(122, 90, 248, 0.8)`}
|
|
isInteractive={!saving}
|
|
>
|
|
{saving ? (
|
|
<ActivityIndicator color="#fff" size="small" />
|
|
) : (
|
|
<>
|
|
<Ionicons name="checkmark-circle" size={20} color="#fff" />
|
|
<ThemedText style={styles.saveButtonText}>保存修改</ThemedText>
|
|
</>
|
|
)}
|
|
</GlassView>
|
|
) : (
|
|
<View style={[styles.saveButton, styles.fallbackSaveButton]}>
|
|
{saving ? (
|
|
<ActivityIndicator color="#fff" size="small" />
|
|
) : (
|
|
<>
|
|
<Ionicons name="checkmark-circle" size={20} color="#fff" />
|
|
<ThemedText style={styles.saveButtonText}>保存修改</ThemedText>
|
|
</>
|
|
)}
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* 时间选择器 Modal */}
|
|
<Modal
|
|
visible={timePickerVisible}
|
|
transparent
|
|
animationType="fade"
|
|
onRequestClose={() => {
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
}}
|
|
>
|
|
<Pressable
|
|
style={styles.pickerBackdrop}
|
|
onPress={() => {
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
}}
|
|
/>
|
|
<View style={[styles.pickerSheet, { backgroundColor: colors.surface }]}>
|
|
<ThemedText style={[styles.pickerTitle, { color: colors.text }]}>
|
|
{editingTimeIndex !== null ? '修改提醒时间' : '添加提醒时间'}
|
|
</ThemedText>
|
|
<DateTimePicker
|
|
value={timePickerDate}
|
|
mode="time"
|
|
display={Platform.OS === 'ios' ? 'spinner' : 'default'}
|
|
onChange={(event, date) => {
|
|
if (Platform.OS === 'ios') {
|
|
if (date) setTimePickerDate(date);
|
|
} else {
|
|
if (event.type === 'set' && date) {
|
|
confirmTime(date);
|
|
} else {
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
}
|
|
}
|
|
}}
|
|
/>
|
|
{Platform.OS === 'ios' && (
|
|
<View style={styles.pickerActions}>
|
|
<Pressable
|
|
onPress={() => {
|
|
setTimePickerVisible(false);
|
|
setEditingTimeIndex(null);
|
|
}}
|
|
style={[styles.pickerBtn, { borderColor: colors.border }]}
|
|
>
|
|
<ThemedText style={[styles.pickerBtnText, { color: colors.textSecondary }]}>
|
|
取消
|
|
</ThemedText>
|
|
</Pressable>
|
|
<Pressable
|
|
onPress={() => confirmTime(timePickerDate)}
|
|
style={[styles.pickerBtn, styles.pickerBtnPrimary, { backgroundColor: colors.primary }]}
|
|
>
|
|
<ThemedText style={[styles.pickerBtnText, { color: colors.onPrimary }]}>
|
|
确定
|
|
</ThemedText>
|
|
</Pressable>
|
|
</View>
|
|
)}
|
|
</View>
|
|
</Modal>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
content: {
|
|
paddingHorizontal: 20,
|
|
gap: 32,
|
|
},
|
|
centered: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
emptyText: {
|
|
fontSize: 16,
|
|
textAlign: 'center',
|
|
},
|
|
medicationNameCard: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 12,
|
|
borderRadius: 20,
|
|
paddingHorizontal: 18,
|
|
paddingVertical: 14,
|
|
},
|
|
medicationNameText: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
section: {
|
|
gap: 16,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
},
|
|
sectionDescription: {
|
|
fontSize: 14,
|
|
lineHeight: 20,
|
|
},
|
|
pickerRow: {
|
|
flexDirection: 'row',
|
|
gap: 16,
|
|
},
|
|
pickerColumn: {
|
|
flex: 1,
|
|
gap: 8,
|
|
},
|
|
pickerLabel: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
textAlign: 'center',
|
|
},
|
|
picker: {
|
|
width: '100%',
|
|
height: 150,
|
|
},
|
|
pickerItem: {
|
|
fontSize: 18,
|
|
height: 150,
|
|
},
|
|
frequencySummary: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 10,
|
|
borderRadius: 16,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 14,
|
|
},
|
|
frequencySummaryText: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
timeList: {
|
|
gap: 12,
|
|
},
|
|
timeItem: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
borderWidth: 1,
|
|
borderRadius: 16,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 14,
|
|
},
|
|
timeValue: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
gap: 10,
|
|
},
|
|
timeText: {
|
|
fontSize: 18,
|
|
fontWeight: '600',
|
|
},
|
|
addTimeButton: {
|
|
borderWidth: 1,
|
|
borderRadius: 16,
|
|
paddingVertical: 14,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 8,
|
|
},
|
|
addTimeLabel: {
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
},
|
|
footerBar: {
|
|
position: 'absolute',
|
|
left: 0,
|
|
right: 0,
|
|
bottom: 0,
|
|
paddingHorizontal: 20,
|
|
paddingTop: 16,
|
|
borderTopWidth: StyleSheet.hairlineWidth,
|
|
borderTopColor: 'rgba(15,23,42,0.06)',
|
|
},
|
|
saveButton: {
|
|
height: 56,
|
|
borderRadius: 24,
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 8,
|
|
overflow: 'hidden',
|
|
},
|
|
fallbackSaveButton: {
|
|
backgroundColor: '#7a5af8',
|
|
shadowColor: 'rgba(122, 90, 248, 0.4)',
|
|
shadowOffset: { width: 0, height: 10 },
|
|
shadowOpacity: 1,
|
|
shadowRadius: 20,
|
|
elevation: 6,
|
|
},
|
|
saveButtonText: {
|
|
fontSize: 17,
|
|
fontWeight: '700',
|
|
color: '#fff',
|
|
},
|
|
pickerBackdrop: {
|
|
flex: 1,
|
|
backgroundColor: 'rgba(15, 23, 42, 0.4)',
|
|
},
|
|
pickerSheet: {
|
|
position: 'absolute',
|
|
left: 20,
|
|
right: 20,
|
|
bottom: 40,
|
|
borderRadius: 24,
|
|
padding: 20,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 10 },
|
|
shadowOpacity: 0.2,
|
|
shadowRadius: 20,
|
|
elevation: 8,
|
|
},
|
|
pickerTitle: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
marginBottom: 16,
|
|
textAlign: 'center',
|
|
},
|
|
pickerActions: {
|
|
flexDirection: 'row',
|
|
gap: 12,
|
|
marginTop: 16,
|
|
},
|
|
pickerBtn: {
|
|
flex: 1,
|
|
paddingVertical: 14,
|
|
borderRadius: 16,
|
|
alignItems: 'center',
|
|
borderWidth: 1,
|
|
},
|
|
pickerBtnPrimary: {
|
|
borderWidth: 0,
|
|
},
|
|
pickerBtnText: {
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
}); |