Add physical btn for carousel navigation,

add keyboard support,
add flipIcon property to CircleIconbtn
This commit is contained in:
Shawn 2023-11-30 10:41:05 -07:00
parent 7feafe35b8
commit d856f91a93
4 changed files with 88 additions and 25 deletions

View File

@ -47,6 +47,7 @@ class CircleIconBtn extends StatelessWidget {
this.color, this.color,
this.size, this.size,
this.iconSize, this.iconSize,
this.flipIcon = false,
required this.semanticLabel, required this.semanticLabel,
}) : super(key: key); }) : super(key: key);
@ -61,6 +62,7 @@ class CircleIconBtn extends StatelessWidget {
final String semanticLabel; final String semanticLabel;
final double? size; final double? size;
final double? iconSize; final double? iconSize;
final bool flipIcon;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -72,7 +74,10 @@ class CircleIconBtn extends StatelessWidget {
size: size, size: size,
bgColor: bgColor ?? defaultColor, bgColor: bgColor ?? defaultColor,
semanticLabel: semanticLabel, semanticLabel: semanticLabel,
child: AppIcon(icon, size: iconSize ?? defaultSize, color: iconColor), child: Transform.scale(
scaleX: flipIcon ? -1 : 1,
child: AppIcon(icon, size: iconSize ?? defaultSize, color: iconColor),
),
); );
} }

View File

@ -105,13 +105,11 @@ class _FullscreenUrlImgViewerState extends State<FullscreenUrlImgViewer> {
semanticLabel: $strings.semanticsNext(''), semanticLabel: $strings.semanticsNext(''),
), ),
Gap($styles.insets.xs), Gap($styles.insets.xs),
Transform.scale( CircleIconBtn(
scaleX: -1, icon: AppIcons.prev,
child: CircleIconBtn( flipIcon: true,
icon: AppIcons.prev, onPressed: page == widget.urls.length - 1 ? null : () => _animateToPage(page + 1),
onPressed: page == widget.urls.length - 1 ? null : () => _animateToPage(page + 1), semanticLabel: $strings.semanticsNext(''),
semanticLabel: $strings.semanticsNext(''),
),
) )
], ],
); );

View File

@ -0,0 +1,54 @@
import 'package:wonders/common_libs.dart';
import 'package:wonders/logic/common/platform_info.dart';
import 'package:wonders/ui/common/app_icons.dart';
import 'package:wonders/ui/common/fullscreen_keyboard_listener.dart';
class PreviousNextNavigation extends StatelessWidget {
const PreviousNextNavigation({super.key, this.onPreviousPressed, this.onNextPressed, required this.child});
final VoidCallback? onPreviousPressed;
final VoidCallback? onNextPressed;
final Widget child;
bool _handleKeyDown(KeyDownEvent event) {
if (event.logicalKey == LogicalKeyboardKey.arrowLeft && onPreviousPressed != null) {
onPreviousPressed?.call();
return true;
}
if (event.logicalKey == LogicalKeyboardKey.arrowRight && onNextPressed != null) {
onNextPressed?.call();
return true;
}
return false;
}
@override
Widget build(BuildContext context) {
Widget buildBtn(String semanticLabel, VoidCallback? onPressed, Alignment align, {bool isNext = false}) {
if (PlatformInfo.isMobile) return child;
return FullScreenKeyboardListener(
onKeyDown: _handleKeyDown,
child: Align(
alignment: align,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: $styles.insets.md),
child: CircleIconBtn(
icon: AppIcons.prev,
onPressed: onPressed,
semanticLabel: semanticLabel,
flipIcon: isNext,
),
),
),
);
}
return Stack(
children: [
child,
//TODO-LOC: Add localization
buildBtn('previous', onPreviousPressed, Alignment.centerLeft),
buildBtn('next', onNextPressed, Alignment.centerRight, isNext: true),
],
);
}
}

View File

@ -4,6 +4,7 @@ import 'package:wonders/ui/common/app_icons.dart';
import 'package:wonders/ui/common/controls/app_header.dart'; import 'package:wonders/ui/common/controls/app_header.dart';
import 'package:wonders/ui/common/controls/app_page_indicator.dart'; import 'package:wonders/ui/common/controls/app_page_indicator.dart';
import 'package:wonders/ui/common/gradient_container.dart'; import 'package:wonders/ui/common/gradient_container.dart';
import 'package:wonders/ui/common/previous_next_navigation.dart';
import 'package:wonders/ui/common/themed_text.dart'; import 'package:wonders/ui/common/themed_text.dart';
import 'package:wonders/ui/common/utils/app_haptics.dart'; import 'package:wonders/ui/common/utils/app_haptics.dart';
import 'package:wonders/ui/screens/home_menu/home_menu.dart'; import 'package:wonders/ui/screens/home_menu/home_menu.dart';
@ -87,11 +88,16 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
void _handlePageIndicatorDotPressed(int index) => _setPageIndex(index); void _handlePageIndicatorDotPressed(int index) => _setPageIndex(index);
void _setPageIndex(int index) { void _setPageIndex(int index, {bool animate = false}) {
if (index == _wonderIndex) return; if (index == _wonderIndex) return;
// To support infinite scrolling, we can't jump directly to the pressed index. Instead, make it relative to our current position. // To support infinite scrolling, we can't jump directly to the pressed index. Instead, make it relative to our current position.
final pos = ((_pageController.page ?? 0) / _numWonders).floor() * _numWonders; final pos = ((_pageController.page ?? 0) / _numWonders).floor() * _numWonders;
_pageController.jumpToPage(pos + index); final newIndex = pos + index;
if (animate == true) {
_pageController.animateToPage(newIndex, duration: $styles.times.med, curve: Curves.easeOutCubic);
} else {
_pageController.jumpToPage(newIndex);
}
} }
void _showDetailsPage() async { void _showDetailsPage() async {
@ -125,24 +131,24 @@ class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateM
return _swipeController.wrapGestureDetector(Container( return _swipeController.wrapGestureDetector(Container(
color: $styles.colors.black, color: $styles.colors.black,
child: Stack( child: PreviousNextNavigation(
children: [ onPreviousPressed: () => _setPageIndex(_wonderIndex - 1, animate: true),
Stack( onNextPressed: () => _setPageIndex(_wonderIndex + 1, animate: true),
children: [ child: Stack(
/// Background children: [
..._buildBgAndClouds(), /// Background
..._buildBgAndClouds(),
/// Wonders Illustrations (main content) /// Wonders Illustrations (main content)
_buildMgPageView(), _buildMgPageView(),
/// Foreground illustrations and gradients /// Foreground illustrations and gradients
_buildFgAndGradients(), _buildFgAndGradients(),
/// Controls that float on top of the various illustrations /// Controls that float on top of the various illustrations
_buildFloatingUi(), _buildFloatingUi(),
], ],
).animate().fadeIn(), ).animate().fadeIn(),
],
), ),
)); ));
} }