|
...
|
...
|
@@ -16,21 +16,77 @@ import '../widgets/sleep_quality_ring.dart'; |
|
|
|
import '../widgets/sleep_summary_card.dart';
|
|
|
|
import '../widgets/sleep_week_report_view.dart';
|
|
|
|
|
|
|
|
class SleepReportView extends StatelessWidget {
|
|
|
|
class SleepReportView extends StatefulWidget {
|
|
|
|
const SleepReportView({
|
|
|
|
super.key,
|
|
|
|
required this.logic,
|
|
|
|
required this.isVip,
|
|
|
|
required this.onSubscribe,
|
|
|
|
this.onReportViewed,
|
|
|
|
this.loadingIndicator = const ReportLoadingIndicator(),
|
|
|
|
});
|
|
|
|
|
|
|
|
final SleepReportLogic logic;
|
|
|
|
final bool isVip;
|
|
|
|
final ValueChanged<String> onSubscribe;
|
|
|
|
final Future<void> Function()? onReportViewed;
|
|
|
|
final Widget loadingIndicator;
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<SleepReportView> createState() => _SleepReportViewState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _SleepReportViewState extends State<SleepReportView> {
|
|
|
|
String? _lastViewedReportKey;
|
|
|
|
bool _viewNotificationScheduled = false;
|
|
|
|
|
|
|
|
@override
|
|
|
|
void didUpdateWidget(covariant SleepReportView oldWidget) {
|
|
|
|
super.didUpdateWidget(oldWidget);
|
|
|
|
if (oldWidget.onReportViewed == null && widget.onReportViewed != null) {
|
|
|
|
_scheduleViewedReportNotification();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _scheduleViewedReportNotification() {
|
|
|
|
if (_viewNotificationScheduled || widget.onReportViewed == null) return;
|
|
|
|
|
|
|
|
final reportKey = _loadedReportKey();
|
|
|
|
if (reportKey == null || reportKey == _lastViewedReportKey) return;
|
|
|
|
|
|
|
|
_viewNotificationScheduled = true;
|
|
|
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
|
|
|
_viewNotificationScheduled = false;
|
|
|
|
if (!mounted || widget.onReportViewed == null) return;
|
|
|
|
if (_loadedReportKey() != reportKey ||
|
|
|
|
_lastViewedReportKey == reportKey) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
_lastViewedReportKey = reportKey;
|
|
|
|
await widget.onReportViewed!();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
String? _loadedReportKey() {
|
|
|
|
if (widget.logic.isLoading.value) return null;
|
|
|
|
|
|
|
|
final period = widget.logic.selectedPeriod.value;
|
|
|
|
final hasData = switch (period) {
|
|
|
|
ReportPeriod.day => widget.logic.report.value?.hasData ?? false,
|
|
|
|
ReportPeriod.week =>
|
|
|
|
widget.logic.weeklyReport.value?.daysWithData.isNotEmpty ?? false,
|
|
|
|
ReportPeriod.month =>
|
|
|
|
widget.logic.monthlyReport.value?.daysWithData.isNotEmpty ?? false,
|
|
|
|
ReportPeriod.year => false,
|
|
|
|
};
|
|
|
|
if (!hasData) return null;
|
|
|
|
|
|
|
|
return '${widget.logic.targetUserId.value ?? 'self'}:'
|
|
|
|
'${period.name}:${widget.logic.selectedDate.value.toIso8601String()}';
|
|
|
|
}
|
|
|
|
|
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
|
|
|
return Container(
|
|
|
|
color: Colors.transparent,
|
|
...
|
...
|
@@ -45,25 +101,27 @@ class SleepReportView extends StatelessWidget { |
|
|
|
const SizedBox(height: 8),
|
|
|
|
Obx(
|
|
|
|
() => ReportPeriodTabBar(
|
|
|
|
selectedPeriod: logic.selectedPeriod.value,
|
|
|
|
onChanged: logic.selectPeriod,
|
|
|
|
lockedPeriods: isVip
|
|
|
|
selectedPeriod: widget.logic.selectedPeriod.value,
|
|
|
|
onChanged: widget.logic.selectPeriod,
|
|
|
|
lockedPeriods: widget.isVip
|
|
|
|
? const {}
|
|
|
|
: const {ReportPeriod.week, ReportPeriod.month},
|
|
|
|
onLockedPeriodTap: (_) => onSubscribe('非会员切换月周-睡眠报告'),
|
|
|
|
onLockedPeriodTap: (_) =>
|
|
|
|
widget.onSubscribe('非会员切换月周-睡眠报告'),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 8),
|
|
|
|
_DateSwitcher(logic: logic),
|
|
|
|
_DateSwitcher(logic: widget.logic),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Expanded(
|
|
|
|
child: Obx(
|
|
|
|
() {
|
|
|
|
if (logic.isLoading.value) {
|
|
|
|
return loadingIndicator;
|
|
|
|
if (widget.logic.isLoading.value) {
|
|
|
|
return widget.loadingIndicator;
|
|
|
|
}
|
|
|
|
_scheduleViewedReportNotification();
|
|
|
|
return CustomScrollView(
|
|
|
|
physics: const ClampingScrollPhysics(),
|
|
|
|
slivers: [
|
|
...
|
...
|
@@ -71,19 +129,21 @@ class SleepReportView extends StatelessWidget { |
|
|
|
padding: const EdgeInsets.fromLTRB(16, 20, 16, 0),
|
|
|
|
sliver: SliverList(
|
|
|
|
delegate: SliverChildListDelegate([
|
|
|
|
if (logic.selectedPeriod.value ==
|
|
|
|
if (widget.logic.selectedPeriod.value ==
|
|
|
|
ReportPeriod.week)
|
|
|
|
SleepWeekReportView(
|
|
|
|
report: logic.weeklyReport.value,
|
|
|
|
report: widget.logic.weeklyReport.value,
|
|
|
|
)
|
|
|
|
else if (logic.selectedPeriod.value ==
|
|
|
|
else if (widget.logic.selectedPeriod.value ==
|
|
|
|
ReportPeriod.month)
|
|
|
|
SleepMonthReportView(
|
|
|
|
monthStart: logic.monthStart,
|
|
|
|
report: logic.monthlyReport.value,
|
|
|
|
monthStart: widget.logic.monthStart,
|
|
|
|
report: widget.logic.monthlyReport.value,
|
|
|
|
)
|
|
|
|
else
|
|
|
|
_DailyReportContent(report: logic.report.value),
|
|
|
|
_DailyReportContent(
|
|
|
|
report: widget.logic.report.value,
|
|
|
|
),
|
|
|
|
const ReportBottomSlogan(),
|
|
|
|
]),
|
|
|
|
),
|
...
|
...
|
|