feature:基本功能
This commit is contained in:
187
client/components/home/DailyReminderModal.tsx
Normal file
187
client/components/home/DailyReminderModal.tsx
Normal file
@@ -0,0 +1,187 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Pressable, StyleSheet, Switch, Text, View } from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import SheetModal from '@/components/ui/SheetModal';
|
||||
import RemindIcon from '@/assets/images/home/Profile/remind.svg';
|
||||
import {
|
||||
getDailyReminderSettings,
|
||||
setDailyReminderSettings,
|
||||
type DailyReminderSettings,
|
||||
} from '@/src/storage/appStorage';
|
||||
|
||||
type Props = {
|
||||
visible: boolean;
|
||||
onClose: () => void;
|
||||
};
|
||||
|
||||
export default function DailyReminderModal({ visible, onClose }: Props) {
|
||||
const { t } = useTranslation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [timesPerDay, setTimesPerDay] = useState(3);
|
||||
const [pushEnabled, setPushEnabled] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
if (!visible) return;
|
||||
setLoading(true);
|
||||
(async () => {
|
||||
const s = await getDailyReminderSettings();
|
||||
if (cancelled) return;
|
||||
setTimesPerDay(s.timesPerDay);
|
||||
setPushEnabled(s.pushEnabled);
|
||||
setLoading(false);
|
||||
})();
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [visible]);
|
||||
|
||||
function clamp(next: number) {
|
||||
return Math.min(10, Math.max(1, next));
|
||||
}
|
||||
|
||||
async function onOk() {
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
const next: DailyReminderSettings = { timesPerDay, pushEnabled };
|
||||
await setDailyReminderSettings(next);
|
||||
setLoading(false);
|
||||
onClose();
|
||||
}
|
||||
|
||||
return (
|
||||
<SheetModal visible={visible} title={t('dailyReminder.title')} onClose={onClose}>
|
||||
<View style={styles.counter}>
|
||||
<Pressable
|
||||
onPress={() => setTimesPerDay((v) => clamp(v - 1))}
|
||||
hitSlop={10}
|
||||
style={styles.circleBtn}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={t('dailyReminder.minus')}
|
||||
>
|
||||
<Text style={styles.circleText}>-</Text>
|
||||
</Pressable>
|
||||
|
||||
<View style={styles.countCenter}>
|
||||
<Text style={styles.countNumber}>{timesPerDay}</Text>
|
||||
<Text style={styles.countUnit}>{t('dailyReminder.timesUnit')}</Text>
|
||||
</View>
|
||||
|
||||
<Pressable
|
||||
onPress={() => setTimesPerDay((v) => clamp(v + 1))}
|
||||
hitSlop={10}
|
||||
style={styles.circleBtn}
|
||||
accessibilityRole="button"
|
||||
accessibilityLabel={t('dailyReminder.plus')}
|
||||
>
|
||||
<Text style={styles.circleText}>+</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<View style={styles.rowLeft}>
|
||||
<View style={styles.rowIcon}>
|
||||
<RemindIcon width={18} height={18} />
|
||||
</View>
|
||||
<Text style={styles.rowText}>{t('dailyReminder.pushLabel')}</Text>
|
||||
</View>
|
||||
<Switch value={pushEnabled} onValueChange={setPushEnabled} />
|
||||
</View>
|
||||
|
||||
<Pressable onPress={onOk} disabled={loading} style={styles.okPressable}>
|
||||
<LinearGradient
|
||||
colors={['#F69F7B', '#F99CC0']}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
style={[styles.okBtn, loading && styles.okBtnDisabled]}
|
||||
>
|
||||
<Text style={styles.okText}>{t('dailyReminder.ok')}</Text>
|
||||
</LinearGradient>
|
||||
</Pressable>
|
||||
</SheetModal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
counter: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
gap: 22,
|
||||
paddingTop: 8,
|
||||
paddingBottom: 22,
|
||||
},
|
||||
circleBtn: {
|
||||
width: 42,
|
||||
height: 42,
|
||||
borderRadius: 21,
|
||||
backgroundColor: 'rgba(244,214,194,0.75)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
circleText: {
|
||||
color: '#5E2A28',
|
||||
fontSize: 20,
|
||||
fontWeight: '700',
|
||||
marginTop: -1,
|
||||
},
|
||||
countCenter: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
gap: 6,
|
||||
},
|
||||
countNumber: {
|
||||
color: '#111',
|
||||
fontSize: 54,
|
||||
fontWeight: '800',
|
||||
letterSpacing: -1,
|
||||
},
|
||||
countUnit: {
|
||||
color: '#111',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
marginBottom: 10,
|
||||
},
|
||||
row: {
|
||||
height: 54,
|
||||
borderRadius: 16,
|
||||
backgroundColor: 'rgba(255,255,255,0.75)',
|
||||
paddingHorizontal: 14,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 18,
|
||||
},
|
||||
rowLeft: { flexDirection: 'row', alignItems: 'center', gap: 10 },
|
||||
rowIcon: {
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 10,
|
||||
backgroundColor: 'rgba(244,214,194,0.55)',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
rowText: {
|
||||
color: '#5E2A28',
|
||||
fontSize: 15,
|
||||
fontWeight: '600',
|
||||
},
|
||||
okPressable: {
|
||||
marginBottom: 6,
|
||||
},
|
||||
okBtn: {
|
||||
height: 52,
|
||||
borderRadius: 26,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
okBtnDisabled: { opacity: 0.7 },
|
||||
okText: {
|
||||
color: '#fff',
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user