Untitled

mail@pastecode.io avatar
unknown
dart
a year ago
7.4 kB
3
Indexable
import 'dart:async';

import 'package:app/features/home/controller/home_list_controller.dart';
import 'package:app/features/home/screen/sections/list/dispensary_list_item.dart';
import 'package:app/model/response/dispensary_dto.dart';
import 'package:app/uikit/assets/icon_path.dart';
import 'package:app/uikit/token/app_color.dart';
import 'package:app/uikit/token/app_radius.dart';
import 'package:app/uikit/token/app_spacing.dart';
import 'package:app/uikit/token/app_text_style.dart';
import 'package:app/uikit/widget/handle_bar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';

class HomeDispensaryList extends GetView<HomeListController> {
  final double collapsedSize;

  final List<DispensaryDTO> dispensaryList;
  final Function() onChangeLocationPressed;
  final Function(DispensaryDTO?) onListItemClick;
  final Function(bool isExpanded) onScrollStateChanged;
  final DraggableScrollableController scrollableController =
      DraggableScrollableController();

  HomeDispensaryList({
    super.key,
    required this.collapsedSize,
    required this.dispensaryList,
    required bool isExpanded,
    required this.onChangeLocationPressed,
    required this.onListItemClick,
    required this.onScrollStateChanged,
  }) {
    controller.isExpanded(isExpanded);
  }

  void _setScrollListener() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      scrollableController.addListener(_scrollListener);
      _handleInitialScrollState();
    });
  }

  void _removeScrollListener() {
    scrollableController.removeListener(_scrollListener);
  }

  void _scrollListener() {
    var offset = scrollableController.size;
    controller.timerTask?.cancel();
    controller.timerTask = Timer(
      const Duration(milliseconds: 150),
      () => onScrollStateChanged.call(offset >= 0.85),
    );
  }

  void _handleInitialScrollState() {
    if (controller.isExpanded.isTrue) {
      _expandSheet();
    } else {
      _collapsedSheet();
    }
  }

  void _collapsedSheet() {
    scrollableController.animateTo(
      collapsedSize,
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeInCubic,
    );
  }

  void _expandSheet() {
    scrollableController.animateTo(
      1,
      duration: const Duration(milliseconds: 300),
      curve: Curves.easeInCubic,
    );
  }

  BorderRadiusGeometry _getTopCornerRadius() {
    return controller.isExpanded.isTrue
        ? BorderRadius.circular(0)
        : const BorderRadius.only(
            topLeft: Radius.circular(AppRadius.radius20),
            topRight: Radius.circular(AppRadius.radius20),
          );
  }

  List<BoxShadow> _getSheetShadow() {
    return controller.isExpanded.isTrue
        ? []
        : [
            BoxShadow(
              color: const Color(0xFF254C5B).withOpacity(0.3),
              offset: const Offset(-1, 0),
              spreadRadius: 0,
              blurRadius: 10,
            ),
          ];
  }

  Widget _buildHeaderSheet() {
    int listSize = dispensaryList.length;

    return Row(
      children: [
        const SizedBox(width: AppSpacing.spacing20),
        Expanded(
          child: Text(
            listSize == 0
                ? 'header_empty_dispensary_nearby'.tr
                : listSize == 1
                    ? 'header_1_dispensary_nearby'.tr
                    : listSize.toString() + 'header_many_dispensary_nearby'.tr,
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
            style: AppTextStyle.labelLarge.apply(
              color: AppColor.neutral,
            ),
            textAlign: controller.isExpanded.isTrue
                ? TextAlign.left
                : TextAlign.center,
          ),
        ),
        Visibility(
          visible: controller.isExpanded.isTrue,
          child: Padding(
            padding: const EdgeInsets.only(
              left: AppSpacing.spacing10,
            ),
            child: Material(
              child: InkWell(
                onTap: onChangeLocationPressed,
                child: Text(
                  'btn_change_location'.tr,
                  style: AppTextStyle.bodyLarge.apply(
                    color: AppColor.primary,
                  ),
                ),
              ),
            ),
          ),
        ),
        const SizedBox(width: AppSpacing.spacing20),
      ],
    );
  }

  Widget _buildEmptyListView() {
    return Visibility(
      visible: dispensaryList.isEmpty,
      child: Column(
        children: [
          const SizedBox(height: AppSpacing.spacing60),
          Text(
            'no_dispensary_nearby'.tr,
            textAlign: TextAlign.center,
            style: AppTextStyle.bodyLarge,
          ),
          const SizedBox(height: AppSpacing.spacing20),
          SvgPicture.asset(
            IconPath.emptyDispensary,
            height: 60,
            width: 60,
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    _removeScrollListener();
    return Container(
      margin: const EdgeInsets.only(top: AppSpacing.spacing10),
      height: MediaQuery.of(context).size.height,
      child: Obx(
        () => DraggableScrollableSheet(
          controller: scrollableController,
          snap: true,
          expand: false,
          minChildSize: collapsedSize,
          maxChildSize: 1,
          initialChildSize: controller.isExpanded.isTrue ? 1 : collapsedSize,
          builder: (BuildContext context, scrollController) {
            _setScrollListener();
            return Container(
              decoration: BoxDecoration(
                color: Colors.white,
                borderRadius: _getTopCornerRadius(),
                boxShadow: _getSheetShadow(),
              ),
              child: SingleChildScrollView(
                controller: scrollController,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    SizedBox(
                      height: 80,
                      width: double.infinity,
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          const SizedBox(height: AppSpacing.spacing10),
                          const HandleBar(),
                          const SizedBox(height: AppSpacing.spacing20),
                          _buildHeaderSheet(),
                          const SizedBox(height: AppSpacing.spacing20),
                        ],
                      ),
                    ),
                    _buildEmptyListView(),
                    ListView.builder(
                      physics: const NeverScrollableScrollPhysics(),
                      padding: EdgeInsets.zero,
                      shrinkWrap: true,
                      itemCount: dispensaryList.length,
                      itemBuilder: (context, index) {
                        return DispensaryListItem(
                          data: dispensaryList.elementAt(index),
                          onItemClick: onListItemClick,
                        );
                      },
                    ),
                  ],
                ),
              ),
            );
          },
        ),
      ),
    );
  }
}