getx icon indicating copy to clipboard operation
getx copied to clipboard

LeftBarIndicator is not rounded when borderRadius set in Snackbar

Open sed1ka opened this issue 2 years ago • 3 comments

When use snackbarStyle.FLOATING and set the borderRadius. the LeftBarIndicator is not rounded

Expected behavior The leftBarIndicator must be rounded when the borderRadius set

Flutter Version: 3.7.6

Getx Version: 4.6.5

Minimal reproduce code

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
// This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Scaffold demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('GeeksforGeeks Scaffold'),
        centerTitle: true,
        backgroundColor: Colors.green,
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Open Snackbar'),
          onPressed: () {
            Get.snackbar(
              "Success",
              "Hello everyone",
              icon: Icon(Icons.check, color: Colors.green),
              backgroundColor: Colors.white,
              snackStyle: SnackStyle.FLOATING,
              borderRadius: 20,
              leftBarIndicatorColor: Colors.green,
            );
          },
        ),
      ),
    );
  }
}

sed1ka avatar Mar 23 '23 01:03 sed1ka

This happens because the Container is missing the clipBehavior on GetSnackBar widget. It should be fixed by simply adding:

clipBehavior: Clip.hardEdge,

to each Container in _containerWithForm() and _containerWithoutForm(). I hope this get fixed in future releases, in the mean time you can create a CustomGetSnackBar that extends GetSnackBar and make your own CustomGetSnackBarState fixing the issue.

luis901101 avatar Aug 25 '23 21:08 luis901101

This happens because the Container is missing the clipBehavior on GetSnackBar widget. It should be fixed by simply adding:

clipBehavior: Clip.hardEdge,

to each Container in _containerWithForm() and _containerWithoutForm(). I hope this get fixed in future releases, in the mean time you can create a CustomGetSnackBar that extends GetSnackBar and make your own CustomGetSnackBarState fixing the issue.

I already create custom class that extend the GetSnackBar but there is no parameter clipBehavior on GetSnackBar. so your suggestion cant be fix the issue

sed1ka avatar Jan 11 '24 03:01 sed1ka

This happens because the Container is missing the clipBehavior on GetSnackBar widget. It should be fixed by simply adding:

clipBehavior: Clip.hardEdge,

to each Container in _containerWithForm() and _containerWithoutForm(). I hope this get fixed in future releases, in the mean time you can create a CustomGetSnackBar that extends GetSnackBar and make your own CustomGetSnackBarState fixing the issue.

I already create custom class that extend the GetSnackBar but there is no parameter clipBehavior on GetSnackBar. so your suggestion cant be fix the issue

Check again my suggestion, of course the GetSnackBar does not have a clipBehavior if it had one, then there would be no need to do the override to anything.

My suggestion is:

create a CustomGetSnackBar that extends GetSnackBar and make your own CustomGetSnackBarState fixing the issue.

The important part is "to make your own CustomGetSnackBarState fixing the issue" which you omitted.

Anyway here you have what my suggestion is:

import 'dart:async';
import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:get/get.dart';

class CustomGetSnackBar extends GetSnackBar {
  const CustomGetSnackBar({
    super.key,
    super.title,
    super.message,
    super.titleText,
    super.messageText,
    super.icon,
    super.shouldIconPulse,
    super.maxWidth,
    super.margin,
    super.padding,
    super.borderRadius,
    super.borderColor,
    super.borderWidth,
    super.backgroundColor,
    super.leftBarIndicatorColor,
    super.boxShadows,
    super.backgroundGradient,
    super.mainButton,
    super.onTap,
    super.duration,
    super.isDismissible,
    super.dismissDirection,
    super.showProgressIndicator,
    super.progressIndicatorController,
    super.progressIndicatorBackgroundColor,
    super.progressIndicatorValueColor,
    super.snackPosition,
    super.snackStyle,
    super.forwardAnimationCurve,
    super.reverseAnimationCurve,
    super.animationDuration,
    super.barBlur,
    super.overlayBlur,
    super.overlayColor,
    super.userInputForm,
    super.snackbarStatus,
  });

  @override
  State createState() => CustomGetSnackBarState();
}

class CustomGetSnackBarState extends State<GetSnackBar>
    with TickerProviderStateMixin {
  AnimationController? _fadeController;
  late Animation<double> _fadeAnimation;

  final Widget _emptyWidget = const SizedBox(width: 0.0, height: 0.0);
  final double _initialOpacity = 1.0;
  final double _finalOpacity = 0.4;

  final Duration _pulseAnimationDuration = const Duration(seconds: 1);

  late bool _isTitlePresent;
  late double _messageTopMargin;

  FocusScopeNode? _focusNode;
  late FocusAttachment _focusAttachment;

  final Completer<Size> _boxHeightCompleter = Completer<Size>();

  late CurvedAnimation _progressAnimation;

  final _backgroundBoxKey = GlobalKey();

  double get buttonPadding {
    if (widget.padding.right - 12 < 0) {
      return 4;
    } else {
      return widget.padding.right - 12;
    }
  }

  RowStyle get _rowStyle {
    if (widget.mainButton != null && widget.icon == null) {
      return RowStyle.action;
    } else if (widget.mainButton == null && widget.icon != null) {
      return RowStyle.icon;
    } else if (widget.mainButton != null && widget.icon != null) {
      return RowStyle.all;
    } else {
      return RowStyle.none;
    }
  }

  @override
  Widget build(BuildContext context) {
    return Align(
      heightFactor: 1.0,
      child: Material(
        color: widget.snackStyle == SnackStyle.FLOATING
            ? Colors.transparent
            : widget.backgroundColor,
        child: SafeArea(
          minimum: widget.snackPosition == SnackPosition.BOTTOM
              ? EdgeInsets.only(
                  bottom: MediaQuery.of(context).viewInsets.bottom)
              : EdgeInsets.only(top: MediaQuery.of(context).padding.top),
          bottom: widget.snackPosition == SnackPosition.BOTTOM,
          top: widget.snackPosition == SnackPosition.TOP,
          left: false,
          right: false,
          child: Stack(
            children: [
              FutureBuilder<Size>(
                future: _boxHeightCompleter.future,
                builder: (context, snapshot) {
                  if (snapshot.hasData) {
                    if (widget.barBlur == 0) {
                      return _emptyWidget;
                    }
                    return ClipRRect(
                      borderRadius: BorderRadius.circular(widget.borderRadius),
                      child: BackdropFilter(
                        filter: ImageFilter.blur(
                            sigmaX: widget.barBlur, sigmaY: widget.barBlur),
                        child: Container(
                          height: snapshot.data!.height,
                          width: snapshot.data!.width,
                          decoration: BoxDecoration(
                            color: Colors.transparent,
                            borderRadius:
                                BorderRadius.circular(widget.borderRadius),
                          ),
                        ),
                      ),
                    );
                  } else {
                    return _emptyWidget;
                  }
                },
              ),
              if (widget.userInputForm != null)
                _containerWithForm()
              else
                _containerWithoutForm()
            ],
          ),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _fadeController?.dispose();
    widget.progressIndicatorController?.removeListener(_updateProgress);
    widget.progressIndicatorController?.dispose();

    _focusAttachment.detach();
    _focusNode!.dispose();
    super.dispose();
  }

  @override
  void initState() {
    super.initState();

    assert(
        widget.userInputForm != null ||
            ((widget.message != null && widget.message!.isNotEmpty) ||
                widget.messageText != null),
        '''
You need to either use message[String], or messageText[Widget] or define a userInputForm[Form] in GetSnackbar''');

    _isTitlePresent = (widget.title != null || widget.titleText != null);
    _messageTopMargin = _isTitlePresent ? 6.0 : widget.padding.top;

    _configureLeftBarFuture();
    _configureProgressIndicatorAnimation();

    if (widget.icon != null && widget.shouldIconPulse) {
      _configurePulseAnimation();
      _fadeController?.forward();
    }

    _focusNode = FocusScopeNode();
    _focusAttachment = _focusNode!.attach(context);
  }

  Widget _buildLeftBarIndicator() {
    if (widget.leftBarIndicatorColor != null) {
      return FutureBuilder<Size>(
        future: _boxHeightCompleter.future,
        builder: (buildContext, snapshot) {
          if (snapshot.hasData) {
            return Container(
              color: widget.leftBarIndicatorColor,
              width: 5.0,
              height: snapshot.data!.height,
            );
          } else {
            return _emptyWidget;
          }
        },
      );
    } else {
      return _emptyWidget;
    }
  }

  void _configureLeftBarFuture() {
    ambiguate(SchedulerBinding.instance)?.addPostFrameCallback(
      (_) {
        final keyContext = _backgroundBoxKey.currentContext;
        if (keyContext != null) {
          final box = keyContext.findRenderObject() as RenderBox;
          _boxHeightCompleter.complete(box.size);
        }
      },
    );
  }

  void _configureProgressIndicatorAnimation() {
    if (widget.showProgressIndicator &&
        widget.progressIndicatorController != null) {
      widget.progressIndicatorController!.addListener(_updateProgress);

      _progressAnimation = CurvedAnimation(
          curve: Curves.linear, parent: widget.progressIndicatorController!);
    }
  }

  void _configurePulseAnimation() {
    _fadeController =
        AnimationController(vsync: this, duration: _pulseAnimationDuration);
    _fadeAnimation = Tween(begin: _initialOpacity, end: _finalOpacity).animate(
      CurvedAnimation(
        parent: _fadeController!,
        curve: Curves.linear,
      ),
    );

    _fadeController!.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        _fadeController!.reverse();
      }
      if (status == AnimationStatus.dismissed) {
        _fadeController!.forward();
      }
    });

    _fadeController!.forward();
  }

  Widget _containerWithForm() {
    return Container(
      key: _backgroundBoxKey,
      clipBehavior: Clip.hardEdge,
      constraints: widget.maxWidth != null
          ? BoxConstraints(maxWidth: widget.maxWidth!)
          : null,
      decoration: BoxDecoration(
        color: widget.backgroundColor,
        gradient: widget.backgroundGradient,
        boxShadow: widget.boxShadows,
        borderRadius: BorderRadius.circular(widget.borderRadius),
        border: widget.borderColor != null
            ? Border.all(
                color: widget.borderColor!,
                width: widget.borderWidth!,
              )
            : null,
      ),
      child: Padding(
        padding: const EdgeInsets.only(
            left: 8.0, right: 8.0, bottom: 8.0, top: 16.0),
        child: FocusScope(
          node: _focusNode,
          autofocus: true,
          child: widget.userInputForm!,
        ),
      ),
    );
  }

  Widget _containerWithoutForm() {
    final iconPadding = widget.padding.left > 16.0 ? widget.padding.left : 0.0;
    final left = _rowStyle == RowStyle.icon || _rowStyle == RowStyle.all
        ? 4.0
        : widget.padding.left;
    final right = _rowStyle == RowStyle.action || _rowStyle == RowStyle.all
        ? 8.0
        : widget.padding.right;
    return Container(
      key: _backgroundBoxKey,
      clipBehavior: Clip.hardEdge,
      constraints: widget.maxWidth != null
          ? BoxConstraints(maxWidth: widget.maxWidth!)
          : null,
      decoration: BoxDecoration(
        color: widget.backgroundColor,
        gradient: widget.backgroundGradient,
        boxShadow: widget.boxShadows,
        borderRadius: BorderRadius.circular(widget.borderRadius),
        border: widget.borderColor != null
            ? Border.all(color: widget.borderColor!, width: widget.borderWidth!)
            : null,
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          widget.showProgressIndicator
              ? LinearProgressIndicator(
                  value: widget.progressIndicatorController != null
                      ? _progressAnimation.value
                      : null,
                  backgroundColor: widget.progressIndicatorBackgroundColor,
                  valueColor: widget.progressIndicatorValueColor,
                )
              : _emptyWidget,
          Row(
            mainAxisSize: MainAxisSize.max,
            children: [
              _buildLeftBarIndicator(),
              if (_rowStyle == RowStyle.icon || _rowStyle == RowStyle.all)
                ConstrainedBox(
                  constraints:
                      BoxConstraints.tightFor(width: 42.0 + iconPadding),
                  child: _getIcon(),
                ),
              Expanded(
                flex: 1,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.stretch,
                  mainAxisSize: MainAxisSize.min,
                  children: <Widget>[
                    if (_isTitlePresent)
                      Padding(
                        padding: EdgeInsets.only(
                          top: widget.padding.top,
                          left: left,
                          right: right,
                        ),
                        child: widget.titleText ??
                            Text(
                              widget.title ?? '',
                              style: const TextStyle(
                                fontSize: 16.0,
                                color: Colors.white,
                                fontWeight: FontWeight.bold,
                              ),
                            ),
                      )
                    else
                      _emptyWidget,
                    Padding(
                      padding: EdgeInsets.only(
                        top: _messageTopMargin,
                        left: left,
                        right: right,
                        bottom: widget.padding.bottom,
                      ),
                      child: widget.messageText ??
                          Text(
                            widget.message ?? '',
                            style: const TextStyle(
                                fontSize: 14.0, color: Colors.white),
                          ),
                    ),
                  ],
                ),
              ),
              if (_rowStyle == RowStyle.action || _rowStyle == RowStyle.all)
                Padding(
                  padding: EdgeInsets.only(right: buttonPadding),
                  child: widget.mainButton,
                ),
            ],
          ),
        ],
      ),
    );
  }

  Widget? _getIcon() {
    if (widget.icon != null && widget.icon is Icon && widget.shouldIconPulse) {
      return FadeTransition(
        opacity: _fadeAnimation,
        child: widget.icon,
      );
    } else if (widget.icon != null) {
      return widget.icon;
    } else {
      return _emptyWidget;
    }
  }

  void _updateProgress() => setState(() {});
}

luis901101 avatar Jan 11 '24 11:01 luis901101