import 'package:flutter/material.dart';

class BottomNavigationDotBar extends StatefulWidget{

  final List<BottomNavigationDotBarItem> items;
  final Color activeColor;
  final Color color;

  /// Called when one of the [items] is tapped.
  ///
  /// The stateful widget that creates the bottom navigation bar needs to keep
  /// track of the index of the selected [BottomNavigationDotBarItem] and call
  /// `setState` to rebuild the bottom navigation bar with the new [currentIndex].
  final ValueChanged<int> onTap;

  /// The index into [items] for the current active [BottomNavigationDotBarItem].
  final int currentIndex;

  const BottomNavigationDotBar({
    @required this.items,
    this.onTap,
    this.currentIndex = 0,
    this.activeColor,
    this.color,
    Key key
  }) : 
    assert(0 <= currentIndex && currentIndex < items.length),
    super(key: key);

  @override
  State<StatefulWidget> createState() => _BottomNavigationDotBarState();

}

class _BottomNavigationDotBarState extends State<BottomNavigationDotBar>{

  GlobalKey _keyBottomBar = GlobalKey();
  double _numPositionBase, _numDifferenceBase, _positionLeftIndicatorDot;
  int _indexPageSelected = 0;
  Color _color, _activeColor;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
    super.initState();
  }

  void _resetState() {
        _color = widget.color ?? Colors.black45;
    _activeColor = widget.activeColor ?? Theme.of(context).primaryColor;
    final sizeBottomBar = (_keyBottomBar.currentContext.findRenderObject() as RenderBox).size;
    _numPositionBase = ((sizeBottomBar.width / widget.items.length));
    _numDifferenceBase = (_numPositionBase - (_numPositionBase / 2) + 2);
    setState(() { 
      _positionLeftIndicatorDot = _numPositionBase - _numDifferenceBase;
    });
  }

   @override
  void didUpdateWidget(BottomNavigationDotBar oldWidget) {
    super.didUpdateWidget(oldWidget);

    // No animated segue if the length of the items list changes.
    if (widget.items.length != oldWidget.items.length) {
      _resetState();
      return;
    }

    if (widget.currentIndex != oldWidget.currentIndex) {
      _changeOptionBottomBar(widget.currentIndex);
    }
  }

  _afterLayout(_) {
    
    _color = widget.color ?? Colors.black45;
    _activeColor = widget.activeColor ?? Theme.of(context).primaryColor;
    final sizeBottomBar = (_keyBottomBar.currentContext.findRenderObject() as RenderBox).size;
    _numPositionBase = ((sizeBottomBar.width / widget.items.length));
    _numDifferenceBase = (_numPositionBase - (_numPositionBase / 2) + 2);
    setState(() { 
      _indexPageSelected = widget.currentIndex;
      _positionLeftIndicatorDot = _numPositionBase - _numDifferenceBase;
      });
  }

  @override
  Widget build(BuildContext context) => Container(
   decoration: BoxDecoration(
    color: Colors.white,
    borderRadius:  BorderRadius.vertical(top: Radius.circular(25)),
    boxShadow: [
      BoxShadow(
        color: Colors.grey.withOpacity(0.2),
        spreadRadius: 1,
        blurRadius: 30,
        offset: Offset(0, -3), // changes position of shadow
      ),
    ],
  ),
  padding: EdgeInsets.only(bottom: 12),
  child: Stack(
    key: _keyBottomBar,
    children: <Widget>[
      Padding(
        padding: EdgeInsets.only(bottom: 10),
        child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: _createNavigationIconButtonList(widget.items.asMap())
        ),
      ),
      AnimatedPositioned(
          child: CircleAvatar(radius: 2.5, backgroundColor: _activeColor),
          duration: Duration(milliseconds: 400),
          curve: Curves.fastOutSlowIn,
          left: _positionLeftIndicatorDot,
          bottom: 0
      ),
    ],
  ),
    );

  List<_NavigationIconButton> _createNavigationIconButtonList(Map<int, BottomNavigationDotBarItem> mapItem){
    List<_NavigationIconButton> children = List<_NavigationIconButton>();
    mapItem.forEach((index, item) =>
        children.add(_NavigationIconButton(item.icon, (index == _indexPageSelected) ? _activeColor : _color, item.hasNotification, item.onTap ,() { widget.onTap(index); }))
    );
    return children;
  }

  void _changeOptionBottomBar(int indexPageSelected){
    if(indexPageSelected != _indexPageSelected){
      setState(() { _positionLeftIndicatorDot = (_numPositionBase * (indexPageSelected+1))-_numDifferenceBase; });
      _indexPageSelected = indexPageSelected;
    }
  }

}

class BottomNavigationDotBarItem{
  final Widget icon;
  final Widget activeIcon;
  final bool hasNotification;
  final NavigationIconButtonTapCallback onTap;
  const BottomNavigationDotBarItem({@required this.icon, Widget activeIcon, this.onTap, this.hasNotification = false}) : activeIcon = activeIcon ?? icon, assert(icon != null);
}

typedef NavigationIconButtonTapCallback = void Function();

class _NavigationIconButton extends StatefulWidget {

  // final IconData _icon;
  final Widget _icon;
  final Color _colorIcon;
  final bool _hasNotification;
  final NavigationIconButtonTapCallback _onTapInternalButton;
  final NavigationIconButtonTapCallback _onTapExternalButton;

  const _NavigationIconButton(this._icon, this._colorIcon, this._hasNotification, this._onTapInternalButton, this._onTapExternalButton, {Key key}): super(key: key);

  @override
  _NavigationIconButtonState createState() => _NavigationIconButtonState();

}

class _NavigationIconButtonState extends State<_NavigationIconButton> with SingleTickerProviderStateMixin {

  AnimationController _controller;
  Animation _scaleAnimation;
  double _opacityIcon = 1;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this, duration: Duration(milliseconds: 400));
    _scaleAnimation = Tween<double>(begin: 1, end: 0.8).animate(_controller);
  }

  @override
  Widget build(BuildContext context) => GestureDetector(
      onTapDown: (_) {
        _controller.forward();
        setState(() { _opacityIcon = 0.7; });
      },
      onTapUp: (_) {
        _controller.reverse();
        setState(() { _opacityIcon = 1; });
      },
      onTapCancel: () {
        _controller.reverse();
        setState(() { _opacityIcon = 1; });
      },
      onTap: () {
        widget._onTapInternalButton();
        widget._onTapExternalButton();
      },
      child: ScaleTransition(
        scale: _scaleAnimation,
        child: AnimatedOpacity(
            opacity: _opacityIcon,
            duration: Duration(milliseconds: 200),
            child: Container(
              alignment: Alignment.bottomCenter,
              color: Colors.transparent,
              width: 65.0,
              height: 43.0,
              child: widget._hasNotification ? new Stack(
                alignment: Alignment.bottomCenter,
                children: <Widget>[
                  // new Icon(widget._icon, color: widget._colorIcon),
                  IconTheme(
                    data: IconThemeData(
                      color: widget._colorIcon,
                    ),
                    child: widget._icon
                  ),
                  new Positioned(
                  top: 0.0,
                  right: 0.0,
                  child: new Stack(
                    children: <Widget>[
                      new Icon(
                        Icons.brightness_1,
                        size: 12.0,
                        color: Colors.red,
                      ),
                    ],
                  ))
                ],
              ): IconTheme(
                    data: IconThemeData(
                      color: widget._colorIcon,
                    ),
                    child: widget._icon
                  ),
            )
        )
      )
  );
}