onboarding_common_widgets.dart 5.2 KB
import 'dart:math' as math;

import 'package:doublefeel_flutter/core/theme/app_theme.dart';
import 'package:flutter/material.dart';

class OnboardingPageScrollBody extends StatelessWidget {
  const OnboardingPageScrollBody({
    super.key,
    required this.child,
    this.horizontalPadding = 16,
    this.topPadding = null,
  });

  final Widget child;
  final double horizontalPadding;
  final double? topPadding;
  @override
  Widget build(BuildContext context) {
    final topPadding =
        this.topPadding ?? (MediaQuery.paddingOf(context).top + 4);
    // this.topPadding ?? (MediaQuery.paddingOf(context).top + 48);
    // final topPadding = 48.0;

    return SingleChildScrollView(
      physics: const ClampingScrollPhysics(),
      padding: EdgeInsets.fromLTRB(
        horizontalPadding,
        topPadding,
        horizontalPadding,
        140,
      ),
      child: child,
    );
  }
}

class OnboardingTitleText extends StatelessWidget {
  const OnboardingTitleText(
    this.text, {
    super.key,
    this.maxWidth = 330,
  });

  final String text;
  final double maxWidth;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ConstrainedBox(
        constraints: BoxConstraints(maxWidth: maxWidth),
        child: Text(
          text,
          textAlign: TextAlign.center,
          style: TextStyle(
            color: context.colors.textPrimary,
            fontSize: 20,
            fontWeight: FontWeight.w600,
            height: 1.3,
            letterSpacing: 0,
          ),
        ),
      ),
    );
  }
}

class OnboardingBodyText extends StatelessWidget {
  const OnboardingBodyText(
    this.text, {
    super.key,
    this.fontSize = 16,
  });

  final String text;
  final double fontSize;

  @override
  Widget build(BuildContext context) {
    return Text(
      text,
      textAlign: TextAlign.center,
      style: TextStyle(
        color: context.colors.textPrimary,
        fontSize: fontSize,
        fontWeight: FontWeight.w400,
        height: 1.38,
        letterSpacing: 0,
      ),
    );
  }
}

class OnboardingBottomButton extends StatelessWidget {
  const OnboardingBottomButton({
    super.key,
    required this.label,
    required this.enabled,
    required this.onPressed,
  });

  final String label;
  final bool enabled;
  final VoidCallback onPressed;

  @override
  Widget build(BuildContext context) {
    final width = math.min(280.0, MediaQuery.sizeOf(context).width - 96);

    return Center(
      child: SizedBox(
        width: width,
        height: 48,
        child: ElevatedButton(
          onPressed: enabled ? onPressed : null,
          style: ElevatedButton.styleFrom(
            backgroundColor: context.colors.primary,
            disabledBackgroundColor:
                context.colors.primary.withValues(alpha: 0.4),
            foregroundColor: Colors.white,
            disabledForegroundColor: Colors.white,
            elevation: 0,
            shadowColor: Colors.transparent,
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(24),
            ),
            textStyle: const TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.w600,
              letterSpacing: 0,
            ),
          ),
          child: Text(
            label,
            maxLines: 1,
            overflow: TextOverflow.ellipsis,
          ),
        ),
      ),
    );
  }
}

class StaggeredEntranceItem extends StatefulWidget {
  const StaggeredEntranceItem({
    super.key,
    required this.index,
    required this.child,
  });

  final int index;
  final Widget child;

  @override
  State<StaggeredEntranceItem> createState() => _StaggeredEntranceItemState();
}

class _StaggeredEntranceItemState extends State<StaggeredEntranceItem> {
  bool _visible = false;

  @override
  void initState() {
    super.initState();
    Future.delayed(Duration(milliseconds: 100 * widget.index), () {
      if (!mounted) {
        return;
      }
      setState(() {
        _visible = true;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedOpacity(
      opacity: _visible ? 1 : 0,
      duration: const Duration(milliseconds: 600),
      curve: Curves.easeOutCubic,
      child: AnimatedPadding(
        duration: const Duration(milliseconds: 600),
        curve: Curves.easeOutCubic,
        padding: _visible
            ? EdgeInsets.zero
            : const EdgeInsets.only(top: 24, bottom: 0),
        child: widget.child,
      ),
    );
  }
}

class OnboardingPageIndicators extends StatelessWidget {
  const OnboardingPageIndicators({
    super.key,
    required this.activeIndex,
    required this.count,
  });

  final int activeIndex;
  final int count;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: List.generate(count, (index) {
        return Container(
          width: 27,
          height: 4,
          margin: const EdgeInsets.symmetric(horizontal: 2),
          decoration: BoxDecoration(
            color: index == activeIndex
                ? context.colors.primary
                : const Color(0xFFD6C7FC),
            borderRadius: BorderRadius.circular(19),
          ),
        );
      }),
    );
  }
}