health_trend_content.dart 7.21 KB
import 'package:flutter/material.dart';
import 'package:get/get.dart';

import '../../../../data/local/user_preferences_storage.dart';
import '../../../routes/app_pages.dart';
import '../../activity_burn_report/controllers/activity_burn_report_logic.dart';
import '../../activity_burn_report/views/activity_burn_report_view.dart';
import '../../home/widgets/trend/trend_type_tab_bar.dart';
import '../../hrv_report/controllers/hrv_report_logic.dart';
import '../../hrv_report/views/hrv_report_view.dart';
import '../../report_common/models/health_report_query.dart';
import '../../report_common/widgets/health_report_subject_scope.dart';
import '../../sleep_report/controllers/sleep_report_logic.dart';
import '../../sleep_report/views/sleep_report_view.dart';

class HealthTrendContent extends StatefulWidget {
  const HealthTrendContent({
    super.key,
    required this.query,
    required this.selectedTypeIndex,
    required this.onTypeChanged,
  });

  final HealthReportQuery query;
  final int selectedTypeIndex;
  final ValueChanged<int> onTypeChanged;

  @override
  State<HealthTrendContent> createState() => _HealthTrendContentState();
}

class _HealthTrendContentState extends State<HealthTrendContent>
    with SingleTickerProviderStateMixin {
  late final TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(
      length: 3,
      vsync: this,
      initialIndex: widget.selectedTypeIndex,
    );
    _tabController.addListener(() {
      if (!_tabController.indexIsChanging) {
        widget.onTypeChanged(_tabController.index);
      }
    });
  }

  @override
  void didUpdateWidget(covariant HealthTrendContent oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.selectedTypeIndex != widget.selectedTypeIndex &&
        _tabController.index != widget.selectedTypeIndex) {
      _tabController.animateTo(widget.selectedTypeIndex);
    }
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final userPrefs = Get.find<UserPreferencesStorage>();
    return Obx(() {
      final preferences = userPrefs.preferences.value;
      final vipInfo = preferences.vipInfo;
      final isVip = vipInfo?.isVip ?? false;
      void openPurchase() => Get.toNamed(Routes.PURCHASE);

      return HealthReportSubjectScope(
        isSelf: widget.query.isSelf,
        child: Column(
          children: [
            TrendTypeTabBar(tabController: _tabController),
            Expanded(
              child: TabBarView(
                controller: _tabController,
                children: [
                  _KeepAliveWrapper(
                    child: _HrvTrendSection(
                      query: widget.query,
                      isVip: isVip,
                      onSubscribe: openPurchase,
                    ),
                  ),
                  _KeepAliveWrapper(
                    child: _ActivityBurnTrendSection(
                      query: widget.query,
                      isVip: isVip,
                      onSubscribe: openPurchase,
                    ),
                  ),
                  _KeepAliveWrapper(
                    child: _SleepTrendSection(
                      query: widget.query,
                      isVip: isVip,
                      onSubscribe: openPurchase,
                    ),
                  ),
                ],
              ),
            ),
          ],
        ),
      );
    });
  }
}

class _HrvTrendSection extends StatefulWidget {
  const _HrvTrendSection({
    required this.query,
    required this.isVip,
    required this.onSubscribe,
  });

  final HealthReportQuery query;
  final bool isVip;
  final VoidCallback onSubscribe;

  @override
  State<_HrvTrendSection> createState() => _HrvTrendSectionState();
}

class _HrvTrendSectionState extends State<_HrvTrendSection> {
  late final HrvReportLogic _logic;

  @override
  void initState() {
    super.initState();
    _logic = HrvReportLogic(initialTargetUserId: widget.query.targetUserId);
    _logic.loadReport();
  }

  @override
  void didUpdateWidget(covariant _HrvTrendSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.query != widget.query) {
      _logic.updateTargetUserId(widget.query.targetUserId);
    }
  }

  @override
  void dispose() {
    _logic.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => HrvReportView(
        logic: _logic,
        isVip: widget.isVip,
        onSubscribe: widget.onSubscribe,
      );
}

class _ActivityBurnTrendSection extends StatefulWidget {
  const _ActivityBurnTrendSection({
    required this.query,
    required this.isVip,
    required this.onSubscribe,
  });

  final HealthReportQuery query;
  final bool isVip;
  final VoidCallback onSubscribe;

  @override
  State<_ActivityBurnTrendSection> createState() =>
      _ActivityBurnTrendSectionState();
}

class _ActivityBurnTrendSectionState extends State<_ActivityBurnTrendSection> {
  late final ActivityBurnReportLogic _logic;

  @override
  void initState() {
    super.initState();
    _logic = ActivityBurnReportLogic(
      initialTargetUserId: widget.query.targetUserId,
    );
    _logic.loadReport();
  }

  @override
  void didUpdateWidget(covariant _ActivityBurnTrendSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.query != widget.query) {
      _logic.updateTargetUserId(widget.query.targetUserId);
    }
  }

  @override
  void dispose() {
    _logic.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => ActivityBurnReportView(
        logic: _logic,
        isVip: widget.isVip,
        onSubscribe: widget.onSubscribe,
      );
}

class _SleepTrendSection extends StatefulWidget {
  const _SleepTrendSection({
    required this.query,
    required this.isVip,
    required this.onSubscribe,
  });

  final HealthReportQuery query;
  final bool isVip;
  final VoidCallback onSubscribe;

  @override
  State<_SleepTrendSection> createState() => _SleepTrendSectionState();
}

class _SleepTrendSectionState extends State<_SleepTrendSection> {
  late final SleepReportLogic _logic;

  @override
  void initState() {
    super.initState();
    _logic = SleepReportLogic(
      initialTargetUserId: widget.query.targetUserId,
    );
    _logic.loadReport();
  }

  @override
  void didUpdateWidget(covariant _SleepTrendSection oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.query != widget.query) {
      _logic.updateTargetUserId(widget.query.targetUserId);
    }
  }

  @override
  void dispose() {
    _logic.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) => SleepReportView(
        logic: _logic,
        isVip: widget.isVip,
        onSubscribe: widget.onSubscribe,
      );
}

class _KeepAliveWrapper extends StatefulWidget {
  const _KeepAliveWrapper({required this.child});

  final Widget child;

  @override
  State<_KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}

class _KeepAliveWrapperState extends State<_KeepAliveWrapper>
    with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return widget.child;
  }
}