Erdnaxela3/bioptim_gui

View on GitHub
gui/lib/screens/generate_code_page/acrobatics/acrobatics_menu.dart

Summary

Maintainability
Test Coverage
import 'package:bioptim_gui/models/acrobatics_data.dart';
import 'package:bioptim_gui/models/acrobatics_request_maker.dart';
import 'package:bioptim_gui/models/ocp_data.dart';
import 'package:bioptim_gui/screens/generate_code_page/acrobatics/generate_acrobatics_phases.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatic_bio_model_chooser.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatic_information.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatic_position_chooser.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatic_sport_type_chooser.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatic_twist_side_chooser.dart';
import 'package:bioptim_gui/widgets/acrobatics/acrobatics_dynamics_chooser.dart';
import 'package:bioptim_gui/widgets/utils/animated_expanding_widget.dart';
import 'package:bioptim_gui/widgets/utils/extensions.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class AcrobaticsMenu extends StatefulWidget {
  const AcrobaticsMenu({super.key, this.columnWidth = 500.0});

  final double columnWidth;

  @override
  State<AcrobaticsMenu> createState() => _AcrobaticsMenuState();
}

class _AcrobaticsMenuState extends State<AcrobaticsMenu> {
  final _verticalScroll = ScrollController();

  AcrobaticsData? _data;

  @override
  void dispose() {
    _verticalScroll.dispose();
    super.dispose();
  }

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

  Future<void> fetchData() async {
    final data = await AcrobaticsRequestMaker().fetchData();
    setState(() {
      _data = data;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_data == null) {
      return const CircularProgressIndicator();
    } else {
      return ChangeNotifierProvider<OCPData>(
        create: (context) => _data!,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            _HeaderBuilder(width: widget.columnWidth),
            const SizedBox(height: 12),
            const Divider(),
            const SizedBox(height: 12),
            _PhaseBuilder(
              width: widget.columnWidth,
            ),
          ],
        ),
      );
    }
  }
}

class _HeaderBuilder extends StatelessWidget {
  const _HeaderBuilder({
    required this.width,
  });

  final double width;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SizedBox(
        width: width,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const SizedBox(height: 12),
            Consumer<OCPData>(builder: (context, data, child) {
              final acrobaticsData = data as AcrobaticsData;
              return Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Row(children: [
                    AcrobaticSportTypeChooser(
                        width: width * 0.35 - 6,
                        defaultValue: acrobaticsData.sportType.capitalize()),
                    const SizedBox(width: 12),
                    AcrobaticsDynamicChooser(width: width * 0.65 - 6),
                  ]),
                  const SizedBox(height: 12),
                  AcrobaticBioModelChooser(
                    width: width,
                    defaultValue: acrobaticsData.modelPath,
                  ),
                  const SizedBox(height: 12),
                  AcrobaticInformation(width: width),
                  const SizedBox(height: 12),
                  Row(
                    children: [
                      SizedBox(
                          width: width / 2 - 6,
                          child: AcrobaticTwistSideChooser(
                            width: width,
                            defaultValue:
                                acrobaticsData.preferredTwistSide.capitalize(),
                          )),
                      const SizedBox(width: 12),
                      SizedBox(
                          width: width / 2 - 6,
                          child: AcrobaticPositionChooser(
                            width: width,
                            defaultValue: acrobaticsData.position.capitalize(),
                          )),
                    ],
                  ),
                  const SizedBox(height: 12),
                  // list acrobaticsData.dofNames
                  AnimatedExpandingWidget(
                    header: SizedBox(
                      width: width,
                      child: const Align(
                        alignment: Alignment.centerLeft,
                        child: Text(
                          "Degrees of freedom",
                          style: TextStyle(
                              fontSize: 16, fontWeight: FontWeight.bold),
                        ),
                      ),
                    ),
                    child: SizedBox(
                      width: width,
                      height: 25.0 * acrobaticsData.dofNames.length.toDouble(),
                      child: ListView.builder(
                        controller: ScrollController(),
                        scrollDirection: Axis.vertical,
                        itemCount: acrobaticsData.dofNames.length,
                        itemBuilder: (context, index) {
                          return SizedBox(
                            width: 100,
                            child: Text(
                              '$index ${acrobaticsData.dofNames[index]}',
                              style: const TextStyle(fontSize: 16),
                            ),
                          );
                        },
                      ),
                    ),
                  ),
                ],
              );
            }),
          ],
        ),
      ),
    );
  }
}

class _PhaseBuilder extends StatefulWidget {
  const _PhaseBuilder({
    required this.width,
  });

  final double width;

  @override
  State<_PhaseBuilder> createState() => _PhaseBuilderState();
}

class _PhaseBuilderState extends State<_PhaseBuilder> {
  final _horizontalScroll = ScrollController();

  @override
  void dispose() {
    _horizontalScroll.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return RawScrollbar(
      controller: _horizontalScroll,
      thumbVisibility: true,
      thumbColor: Theme.of(context).colorScheme.secondary,
      thickness: 8,
      radius: const Radius.circular(25),
      child: SingleChildScrollView(
        controller: _horizontalScroll,
        scrollDirection: Axis.horizontal,
        child: Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              SomersaultGenerationMenu(
                width: widget.width,
              ),
            ]),
      ),
    );
  }
}