Add physical btn for carousel navigation,
add keyboard support, add flipIcon property to CircleIconbtn
This commit is contained in:
parent
7feafe35b8
commit
d856f91a93
@ -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),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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(''),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
54
lib/ui/common/previous_next_navigation.dart
Normal file
54
lib/ui/common/previous_next_navigation.dart
Normal 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),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -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(),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user