From 7e154b6d031ea1239db16a0d7664700288d79f5a Mon Sep 17 00:00:00 2001 From: ALEZ-DEV Date: Wed, 22 May 2024 22:07:46 +0200 Subject: [PATCH] Display the steps correctly in setup --- .../lib/providers/game_state_provider.dart | 3 +- .../lib/screens/setup_screen.dart | 20 +- .../lib/screens/setups/proton_screen.dart | 28 --- .../lib/screens/setups/steps_screen.dart | 72 ++++++ .../selectable_yaru_expansion_panel.dart | 229 ++++++++++++++++++ 5 files changed, 305 insertions(+), 47 deletions(-) delete mode 100644 babylonia_terminal_launcher/lib/screens/setups/proton_screen.dart create mode 100644 babylonia_terminal_launcher/lib/screens/setups/steps_screen.dart create mode 100644 babylonia_terminal_launcher/lib/widgets/selectable_yaru_expansion_panel.dart diff --git a/babylonia_terminal_launcher/lib/providers/game_state_provider.dart b/babylonia_terminal_launcher/lib/providers/game_state_provider.dart index bc8676b..43e6778 100644 --- a/babylonia_terminal_launcher/lib/providers/game_state_provider.dart +++ b/babylonia_terminal_launcher/lib/providers/game_state_provider.dart @@ -26,6 +26,7 @@ class GameStateProvider with ChangeNotifier { bool hasToSetup() { return _gameState == States.ProtonNotInstalled || - _gameState == States.DXVKNotInstalled; + _gameState == States.DXVKNotInstalled || + _gameState == States.DependecieNotInstalled; } } diff --git a/babylonia_terminal_launcher/lib/screens/setup_screen.dart b/babylonia_terminal_launcher/lib/screens/setup_screen.dart index 59954ac..f6e63f9 100644 --- a/babylonia_terminal_launcher/lib/screens/setup_screen.dart +++ b/babylonia_terminal_launcher/lib/screens/setup_screen.dart @@ -1,39 +1,23 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import './../messages/game_state.pb.dart'; -import './../providers/game_state_provider.dart'; import './../providers/settings_provider.dart'; import './setups/welcome_screen.dart'; -import './setups/proton_screen.dart'; +import 'setups/steps_screen.dart'; class SetupScreen extends StatelessWidget { const SetupScreen({super.key}); @override Widget build(BuildContext context) { - final gameStateProvider = Provider.of(context); final settingsProvider = Provider.of(context); - final Widget content; - if (settingsProvider.firstTime) { - content = const WelcomeScreen(); - } else { - switch (gameStateProvider.gameState) { - case States.ProtonNotInstalled: - content = const ProtonScreen(); - case States.DXVKNotInstalled: - content = const Text('DXVK'); - default: - content = const Text('???'); - } - } return Scaffold( appBar: AppBar( title: const Text("Babylonia Terminal"), centerTitle: true, ), - body: content, + body: settingsProvider.firstTime ? const WelcomeScreen() : StepsScreen(), ); } } diff --git a/babylonia_terminal_launcher/lib/screens/setups/proton_screen.dart b/babylonia_terminal_launcher/lib/screens/setups/proton_screen.dart deleted file mode 100644 index f7bc8d4..0000000 --- a/babylonia_terminal_launcher/lib/screens/setups/proton_screen.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:yaru/yaru.dart'; - -class ProtonScreen extends StatelessWidget { - const ProtonScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Center( - child: ConstrainedBox( - constraints: const BoxConstraints( - maxHeight: 600, - maxWidth: 750, - ), - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 25.0), - child: YaruSection( - headline: Center( - child: Text('Proton'), - ), - child: Text('Some content'), - ), - ), - ), - ); - } -} diff --git a/babylonia_terminal_launcher/lib/screens/setups/steps_screen.dart b/babylonia_terminal_launcher/lib/screens/setups/steps_screen.dart new file mode 100644 index 0000000..4852be9 --- /dev/null +++ b/babylonia_terminal_launcher/lib/screens/setups/steps_screen.dart @@ -0,0 +1,72 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:provider/provider.dart'; + +import './../../messages/game_state.pb.dart'; +import './../../providers/providers.dart'; +import './../../widgets/selectable_yaru_expansion_panel.dart'; +import './../../widgets/simple_button.dart'; + +class StepsScreen extends StatelessWidget { + StepsScreen({super.key}); + final SectionController controller = SectionController(selectedItem: 0); + + @override + Widget build(BuildContext context) { + final gameStateProvider = Provider.of(context); + switch (gameStateProvider.gameState) { + case States.ProtonNotInstalled: + controller.updateSection(0); + break; + case States.DXVKNotInstalled: + controller.updateSection(1); + break; + case States.DependecieNotInstalled: + controller.updateSection(2); + break; + } + + return Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 600, + maxWidth: 750, + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 25.0), + child: SelectableYaruExpansionPanel( + controller: controller, + headers: const [ + Text("Proton"), + Text("DXVK"), + Text("Dependecies"), + ], + children: const [ + Padding( + padding: EdgeInsets.all(40.0), + child: Text("Proton"), + ), + Padding( + padding: EdgeInsets.all(40.0), + child: Text("DXVK"), + ), + Padding( + padding: EdgeInsets.all(40.0), + child: Text("Dependecies"), + ), + ], + ), + ), + ), + SimpleButton( + onPressed: () => gameStateProvider.updateGameState(), + child: const Text('update'), + ), + ], + ), + ); + } +} diff --git a/babylonia_terminal_launcher/lib/widgets/selectable_yaru_expansion_panel.dart b/babylonia_terminal_launcher/lib/widgets/selectable_yaru_expansion_panel.dart new file mode 100644 index 0000000..b9ecc62 --- /dev/null +++ b/babylonia_terminal_launcher/lib/widgets/selectable_yaru_expansion_panel.dart @@ -0,0 +1,229 @@ +// This file has been literally copied from https://github.com/ubuntu/yaru.dart/blob/main/lib/src/widgets/yaru_expansion_panel.dart +// and https://github.com/ubuntu/yaru.dart/blob/main/lib/src/widgets/yaru_expandable.dart +// Just want to make some change to it for specific needs instead of contributing to it, because I'm too lazy for that and I think they don't want these change + +import 'package:flutter/material.dart'; + +import 'package:yaru/constants.dart'; +import 'package:yaru/widgets.dart'; + +class SectionController extends ChangeNotifier { + int selectedItem = 0; + Function()? onChange; + + SectionController({required this.selectedItem}); + + void updateSection(int newSelectedItem) { + selectedItem = newSelectedItem; + notifyListeners(); + if (onChange != null) { + onChange!(); + } + } +} + +class SelectableYaruExpansionPanel extends StatefulWidget { + const SelectableYaruExpansionPanel({ + super.key, + required this.controller, + required this.children, + this.borderRadius = + const BorderRadius.all(Radius.circular(kYaruContainerRadius)), + this.border, + required this.headers, + this.width, + this.height, + this.padding, + this.margin, + this.expandIconPadding = const EdgeInsets.all(10), + this.headerPadding = const EdgeInsets.only(left: 20), + this.color, + this.placeDividers = true, + this.expandIcon, + this.shrinkWrap = true, + this.scrollPhysics = const ClampingScrollPhysics(), + this.collapseOnExpand = true, + }) : assert(headers.length == children.length); + + final SectionController controller; + final List children; + final List headers; + final BorderRadius borderRadius; + final BoxBorder? border; + final double? width; + final double? height; + final EdgeInsetsGeometry? padding; + final EdgeInsetsGeometry? margin; + final EdgeInsetsGeometry expandIconPadding; + final EdgeInsetsGeometry headerPadding; + final Color? color; + final bool placeDividers; + final Widget? expandIcon; + final bool shrinkWrap; + final ScrollPhysics scrollPhysics; + final bool collapseOnExpand; + + @override + State createState() => + _SelectableYaruExpansionPanelState(); +} + +class _SelectableYaruExpansionPanelState + extends State { + late List _expandedStore; + + @override + void initState() { + super.initState(); + widget.controller.onChange = widget.collapseOnExpand + ? () { + _expandedStore[widget.controller.selectedItem]; + for (var n = 0; n < _expandedStore.length; n++) { + if (_expandedStore[n]) { + setState(() => _expandedStore[n] = false); + } + } + } + : null; + _expandedStore = + List.generate(widget.children.length, (index) => false); + } + + @override + Widget build(BuildContext context) { + assert(widget.children.length == widget.headers.length); + + _expandedStore[widget.controller.selectedItem] = true; + + return YaruBorderContainer( + border: widget.border, + borderRadius: widget.borderRadius, + color: widget.color, + width: widget.width, + height: widget.height, + padding: widget.padding, + margin: widget.margin, + child: widget.placeDividers + ? ListView.separated( + shrinkWrap: widget.shrinkWrap, + physics: widget.scrollPhysics, + itemCount: widget.children.length, + itemBuilder: _itemBuilder, + separatorBuilder: (context, index) { + if (index != widget.children.length - 1) { + return const Padding( + padding: EdgeInsets.symmetric(vertical: 1), + child: Divider(), + ); + } else { + return const SizedBox.shrink(); + } + }, + ) + : ListView.builder( + shrinkWrap: widget.shrinkWrap, + physics: widget.scrollPhysics, + itemCount: widget.children.length, + itemBuilder: _itemBuilder, + ), + ); + } + + Widget? _itemBuilder(context, index) { + return YaruExpandable( + expandIconPadding: widget.expandIconPadding, + isExpanded: _expandedStore[index], + header: Padding( + padding: widget.headerPadding, + child: widget.headers[index], + ), + child: widget.children[index], + ); + } +} + +const _kAnimationDuration = Duration(milliseconds: 250); +const _kAnimationCurve = Curves.easeInOutCubic; + +class YaruExpandable extends StatefulWidget { + const YaruExpandable({ + super.key, + required this.header, + this.expandIconPadding = EdgeInsets.zero, + required this.child, + this.collapsedChild, + this.gapHeight = 4.0, + this.isExpanded = false, + this.onChange, + }); + + final Widget header; + final EdgeInsetsGeometry expandIconPadding; + final Widget child; + final Widget? collapsedChild; + final double gapHeight; + final bool isExpanded; + final ValueChanged? onChange; + + @override + State createState() => _YaruExpandableState(); +} + +class _YaruExpandableState extends State { + late bool _isExpanded; + + @override + void initState() { + _isExpanded = widget.isExpanded; + super.initState(); + } + + @override + void didUpdateWidget(YaruExpandable oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.isExpanded != widget.isExpanded) { + _isExpanded = widget.isExpanded; + } + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + widget.header, + Padding( + padding: widget.expandIconPadding, + child: const SizedBox( + height: 36, + width: 36, + ), + ), + ], + ), + AnimatedCrossFade( + firstChild: _buildChild(widget.child), + secondChild: widget.collapsedChild != null + ? _buildChild(widget.collapsedChild!) + : Container(), + crossFadeState: _isExpanded + ? CrossFadeState.showFirst + : CrossFadeState.showSecond, + sizeCurve: _kAnimationCurve, + duration: _kAnimationDuration, + ), + ], + ); + } + + Widget _buildChild(Widget child) { + return Column( + children: [ + SizedBox(height: widget.gapHeight), + child, + ], + ); + } +}