Erdnaxela3/bioptim_gui

View on GitHub
gui/lib/widgets/edit_bounds/init_guess_slider.dart

Summary

Maintainability
Test Coverage
import 'package:bioptim_gui/models/decision_variable_value_type.dart';
import 'package:bioptim_gui/models/decision_variables_type.dart';
import 'package:bioptim_gui/models/ocp_data.dart';
import 'package:bioptim_gui/models/variables.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:syncfusion_flutter_sliders/sliders.dart';

class InitGuessSlider extends StatefulWidget {
  const InitGuessSlider({
    super.key,
    required this.phaseIndex,
    required this.decisionVariableType,
    required this.variableIndex,
    required this.dofIndex,
    required this.nodeIndex,
  });

  final int phaseIndex;
  final DecisionVariableType decisionVariableType;
  final int variableIndex;
  final int dofIndex;
  final int nodeIndex;

  @override
  State<InitGuessSlider> createState() => _InitGuessSliderState();
}

class _InitGuessSliderState extends State<InitGuessSlider> {
  // Add a key to force recreation when phaseIndex changes
  Key get key => ValueKey<int>(widget.phaseIndex);
  double? _value;
  double _rangeMinValue = -1;
  double _rangeMaxValue = 1;

  @override
  void initState() {
    super.initState();
    final Variable variable =
        widget.decisionVariableType == DecisionVariableType.state
            ? context
                .read<OCPData>()
                .phasesInfo[widget.phaseIndex]
                .stateVariables[widget.variableIndex]
            : context
                .read<OCPData>()
                .phasesInfo[widget.phaseIndex]
                .controlVariables[widget.variableIndex];

    final int initGuessNbNodes = variable.initialGuess[widget.dofIndex].length;

    int boudCorrespondingNode = widget.nodeIndex;

    if (initGuessNbNodes == 2 && widget.nodeIndex != 0) {
      boudCorrespondingNode =
          variable.bounds.minBounds[widget.dofIndex].length - 1;
    }

    final double boundMinValue =
        variable.bounds.minBounds[widget.dofIndex][boudCorrespondingNode];
    final double boundMaxValue =
        variable.bounds.maxBounds[widget.dofIndex][boudCorrespondingNode];
    const double margin = 0.01;

    _rangeMinValue = boundMinValue - margin;
    _rangeMaxValue = boundMaxValue + margin;
    _value = variable.initialGuess[widget.dofIndex][widget.nodeIndex];
  }

  void _updateRange() {
    int boudCorrespondingNode = widget.nodeIndex;

    final Variable variable =
        widget.decisionVariableType == DecisionVariableType.state
            ? context
                .read<OCPData>()
                .phasesInfo[widget.phaseIndex]
                .stateVariables[widget.variableIndex]
            : context
                .read<OCPData>()
                .phasesInfo[widget.phaseIndex]
                .controlVariables[widget.variableIndex];

    final int initGuessNbNodes = variable.initialGuess[widget.dofIndex].length;

    if (initGuessNbNodes == 2 && widget.nodeIndex != 0) {
      boudCorrespondingNode =
          variable.bounds.minBounds[widget.dofIndex].length - 1;
    }

    final double boundMinValue =
        variable.bounds.minBounds[widget.dofIndex][boudCorrespondingNode];
    final double boundMaxValue =
        variable.bounds.maxBounds[widget.dofIndex][boudCorrespondingNode];
    const double margin = 0.01;

    setState(() {
      _rangeMinValue = boundMinValue - margin;
      _rangeMaxValue = boundMaxValue + margin;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Consumer<OCPData>(builder: (context, data, child) {
      return SfSlider.vertical(
        activeColor: Colors.black,
        inactiveColor: Colors.black,
        min: _rangeMinValue,
        max: _rangeMaxValue,
        value: _value,
        interval: (_rangeMinValue.abs() + _rangeMaxValue.abs()) / 5,
        showTicks: true,
        showLabels: true,
        onChangeEnd: (value) {
          data.updateDecisionVariableValue(
            widget.phaseIndex,
            widget.decisionVariableType,
            DecisionVariableValueType.initGuess,
            widget.variableIndex,
            widget.dofIndex,
            widget.nodeIndex,
            value,
          );

          _updateRange();
        },
        onChanged: (dynamic value) {
          setState(() {
            _value = value;
          });
        },
      );
    });
  }
}