enum HealthReminderMetric { bloodPressure, heartRate, glucose, spo2, weight } extension HealthReminderMetricX on HealthReminderMetric { String get label => switch (this) { HealthReminderMetric.bloodPressure => '血压', HealthReminderMetric.heartRate => '心率', HealthReminderMetric.glucose => '血糖', HealthReminderMetric.spo2 => '血氧', HealthReminderMetric.weight => '体重', }; String get backendField => switch (this) { HealthReminderMetric.bloodPressure => 'healthRecordReminderBloodPressure', HealthReminderMetric.heartRate => 'healthRecordReminderHeartRate', HealthReminderMetric.glucose => 'healthRecordReminderGlucose', HealthReminderMetric.spo2 => 'healthRecordReminderSpO2', HealthReminderMetric.weight => 'healthRecordReminderWeight', }; } class NotificationPrefs { final bool pushEnabled; final bool medicationReminder; final bool followUpReminder; final bool doctorReply; final bool abnormalAlert; final bool dndEnabled; final int dndStartMinutes; final int dndEndMinutes; final bool healthRecordReminder; final Set enabledHealthMetrics; const NotificationPrefs({ required this.pushEnabled, required this.medicationReminder, required this.followUpReminder, required this.doctorReply, required this.abnormalAlert, required this.dndEnabled, required this.dndStartMinutes, required this.dndEndMinutes, required this.healthRecordReminder, required this.enabledHealthMetrics, }); factory NotificationPrefs.fromJson(Map json) { final metrics = {}; for (final metric in HealthReminderMetric.values) { if ((json[metric.backendField] as bool?) ?? true) metrics.add(metric); } return NotificationPrefs( pushEnabled: (json['pushEnabled'] as bool?) ?? true, medicationReminder: (json['medicationReminder'] as bool?) ?? true, followUpReminder: (json['followUpReminder'] as bool?) ?? true, doctorReply: (json['doctorReply'] as bool?) ?? false, abnormalAlert: (json['abnormalAlert'] as bool?) ?? true, dndEnabled: (json['dndEnabled'] as bool?) ?? false, dndStartMinutes: (json['dndStartMinutes'] as num?)?.toInt() ?? 22 * 60, dndEndMinutes: (json['dndEndMinutes'] as num?)?.toInt() ?? 8 * 60, healthRecordReminder: (json['healthRecordReminder'] as bool?) ?? true, enabledHealthMetrics: Set.unmodifiable(metrics), ); } } class NotificationPrefsViewState { final NotificationPrefs? prefs; final bool loading; final String? loadError; final Set savingKeys; const NotificationPrefsViewState({ this.prefs, this.loading = false, this.loadError, this.savingKeys = const {}, }); NotificationPrefsViewState copyWith({ NotificationPrefs? prefs, bool? loading, String? loadError, bool clearLoadError = false, Set? savingKeys, }) => NotificationPrefsViewState( prefs: prefs ?? this.prefs, loading: loading ?? this.loading, loadError: clearLoadError ? null : loadError ?? this.loadError, savingKeys: savingKeys ?? this.savingKeys, ); } String healthMetricSummary(Set metrics) { if (metrics.isEmpty) return '至少选择一项'; if (metrics.length == HealthReminderMetric.values.length) return '全部指标'; return HealthReminderMetric.values .where(metrics.contains) .map((metric) => metric.label) .join('、'); } Map healthMetricUpdatePayload( Set metrics, ) => { for (final metric in HealthReminderMetric.values) metric.backendField: metrics.contains(metric), };