Add scroll wheel support for intro screen
This commit is contained in:
parent
7318ce7d9a
commit
b6e35f6f92
@ -1,6 +1,7 @@
|
|||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:wonders/common_libs.dart';
|
import 'package:wonders/common_libs.dart';
|
||||||
import 'package:wonders/ui/common/app_icons.dart';
|
import 'package:wonders/ui/common/app_icons.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/static_text_scale.dart';
|
import 'package:wonders/ui/common/static_text_scale.dart';
|
||||||
@ -25,6 +26,8 @@ class _IntroScreenState extends State<IntroScreen> {
|
|||||||
late final PageController _pageController = PageController()..addListener(_handlePageChanged);
|
late final PageController _pageController = PageController()..addListener(_handlePageChanged);
|
||||||
final ValueNotifier<int> _currentPage = ValueNotifier(0);
|
final ValueNotifier<int> _currentPage = ValueNotifier(0);
|
||||||
bool get _isOnLastPage => _currentPage.value.round() == pageData.length - 1;
|
bool get _isOnLastPage => _currentPage.value.round() == pageData.length - 1;
|
||||||
|
bool get _isOnFirstPage => _currentPage.value.round() == 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_pageController.dispose();
|
_pageController.dispose();
|
||||||
@ -48,12 +51,17 @@ class _IntroScreenState extends State<IntroScreen> {
|
|||||||
duration: $styles.times.fast, curve: Curves.easeOut);
|
duration: $styles.times.fast, curve: Curves.easeOut);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleNavTextDoubleTapped() {
|
void _handleNavTextSemanticTap() => _incrementPage(1);
|
||||||
|
|
||||||
|
void _incrementPage(int dir){
|
||||||
final int current = _pageController.page!.round();
|
final int current = _pageController.page!.round();
|
||||||
if (_isOnLastPage) return;
|
if (_isOnLastPage && dir > 0) return;
|
||||||
_pageController.animateToPage(current + 1, duration: 250.ms, curve: Curves.easeIn);
|
if (_isOnFirstPage && dir < 0) return;
|
||||||
|
_pageController.animateToPage(current + dir, duration: 250.ms, curve: Curves.easeIn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _handleScrollWheel(double delta) => _incrementPage(delta >0? 1 : -1);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// Set the page data, as strings may have changed based on locale
|
// Set the page data, as strings may have changed based on locale
|
||||||
@ -70,96 +78,103 @@ class _IntroScreenState extends State<IntroScreen> {
|
|||||||
final List<Widget> pages = pageData.map((e) => _Page(data: e)).toList();
|
final List<Widget> pages = pageData.map((e) => _Page(data: e)).toList();
|
||||||
|
|
||||||
/// Return resulting widget tree
|
/// Return resulting widget tree
|
||||||
return DefaultTextColor(
|
return Listener(
|
||||||
color: $styles.colors.offWhite,
|
onPointerSignal: (signal){
|
||||||
child: Container(
|
if(signal is PointerScrollEvent){
|
||||||
color: $styles.colors.black,
|
_handleScrollWheel(signal.scrollDelta.dy);
|
||||||
child: SafeArea(
|
}
|
||||||
child: Animate(
|
},
|
||||||
delay: 500.ms,
|
child: DefaultTextColor(
|
||||||
effects: const [FadeEffect()],
|
color: $styles.colors.offWhite,
|
||||||
child: Stack(
|
child: Container(
|
||||||
children: [
|
color: $styles.colors.black,
|
||||||
// page view with title & description:
|
child: SafeArea(
|
||||||
MergeSemantics(
|
child: Animate(
|
||||||
child: Semantics(
|
delay: 500.ms,
|
||||||
onIncrease: () => _handleSemanticSwipe(1),
|
effects: const [FadeEffect()],
|
||||||
onDecrease: () => _handleSemanticSwipe(-1),
|
child: Stack(
|
||||||
child: PageView(
|
children: [
|
||||||
controller: _pageController,
|
// page view with title & description:
|
||||||
children: pages,
|
MergeSemantics(
|
||||||
onPageChanged: (_) => AppHaptics.lightImpact(),
|
child: Semantics(
|
||||||
),
|
onIncrease: () => _handleSemanticSwipe(1),
|
||||||
),
|
onDecrease: () => _handleSemanticSwipe(-1),
|
||||||
),
|
child: PageView(
|
||||||
|
controller: _pageController,
|
||||||
IgnorePointer(
|
children: pages,
|
||||||
ignoringSemantics: false,
|
onPageChanged: (_) => AppHaptics.lightImpact(),
|
||||||
child: Column(children: [
|
|
||||||
Spacer(),
|
|
||||||
|
|
||||||
// logo:
|
|
||||||
Semantics(
|
|
||||||
header: true,
|
|
||||||
child: Container(
|
|
||||||
height: _logoHeight,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: _WonderousLogo(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// masked image:
|
|
||||||
SizedBox(
|
|
||||||
height: _imageSize,
|
|
||||||
width: _imageSize,
|
|
||||||
child: ValueListenableBuilder<int>(
|
|
||||||
valueListenable: _currentPage,
|
|
||||||
builder: (_, value, __) {
|
|
||||||
return AnimatedSwitcher(
|
|
||||||
duration: $styles.times.slow,
|
|
||||||
child: KeyedSubtree(
|
|
||||||
key: ValueKey(value), // so AnimatedSwitcher sees it as a different child.
|
|
||||||
child: _PageImage(data: pageData[value]),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
|
|
||||||
// placeholder gap for text:
|
|
||||||
Gap(_IntroScreenState._textHeight),
|
|
||||||
|
|
||||||
// page indicator:
|
|
||||||
Container(
|
|
||||||
height: _pageIndicatorHeight,
|
|
||||||
alignment: Alignment(0.0, 0),
|
|
||||||
child: AppPageIndicator(
|
|
||||||
count: pageData.length, controller: _pageController, color: $styles.colors.offWhite),
|
|
||||||
),
|
|
||||||
|
|
||||||
Spacer(flex: 2),
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
|
|
||||||
// Build a cpl overlays to hide the content when swiping on very wide screens
|
|
||||||
_buildHzGradientOverlay(left: true),
|
|
||||||
_buildHzGradientOverlay(),
|
|
||||||
|
|
||||||
// finish button:
|
|
||||||
Positioned(
|
|
||||||
right: $styles.insets.lg,
|
|
||||||
bottom: $styles.insets.lg,
|
|
||||||
child: _buildFinishBtn(context),
|
|
||||||
),
|
|
||||||
|
|
||||||
// nav help text:
|
|
||||||
BottomCenter(
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(bottom: $styles.insets.lg),
|
|
||||||
child: _buildNavText(context),
|
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
IgnorePointer(
|
||||||
|
ignoringSemantics: false,
|
||||||
|
child: Column(children: [
|
||||||
|
Spacer(),
|
||||||
|
|
||||||
|
// logo:
|
||||||
|
Semantics(
|
||||||
|
header: true,
|
||||||
|
child: Container(
|
||||||
|
height: _logoHeight,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: _WonderousLogo(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// masked image:
|
||||||
|
SizedBox(
|
||||||
|
height: _imageSize,
|
||||||
|
width: _imageSize,
|
||||||
|
child: ValueListenableBuilder<int>(
|
||||||
|
valueListenable: _currentPage,
|
||||||
|
builder: (_, value, __) {
|
||||||
|
return AnimatedSwitcher(
|
||||||
|
duration: $styles.times.slow,
|
||||||
|
child: KeyedSubtree(
|
||||||
|
key: ValueKey(value), // so AnimatedSwitcher sees it as a different child.
|
||||||
|
child: _PageImage(data: pageData[value]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// placeholder gap for text:
|
||||||
|
Gap(_IntroScreenState._textHeight),
|
||||||
|
|
||||||
|
// page indicator:
|
||||||
|
Container(
|
||||||
|
height: _pageIndicatorHeight,
|
||||||
|
alignment: Alignment(0.0, 0),
|
||||||
|
child: AppPageIndicator(
|
||||||
|
count: pageData.length, controller: _pageController, color: $styles.colors.offWhite),
|
||||||
|
),
|
||||||
|
|
||||||
|
Spacer(flex: 2),
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
|
||||||
|
// Build a cpl overlays to hide the content when swiping on very wide screens
|
||||||
|
_buildHzGradientOverlay(left: true),
|
||||||
|
_buildHzGradientOverlay(),
|
||||||
|
|
||||||
|
// finish button:
|
||||||
|
Positioned(
|
||||||
|
right: $styles.insets.lg,
|
||||||
|
bottom: $styles.insets.lg,
|
||||||
|
child: _buildFinishBtn(context),
|
||||||
|
),
|
||||||
|
|
||||||
|
// nav help text:
|
||||||
|
BottomCenter(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(bottom: $styles.insets.lg),
|
||||||
|
child: _buildNavText(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -215,7 +230,7 @@ class _IntroScreenState extends State<IntroScreen> {
|
|||||||
duration: $styles.times.fast,
|
duration: $styles.times.fast,
|
||||||
child: Semantics(
|
child: Semantics(
|
||||||
onTapHint: $strings.introSemanticNavigate,
|
onTapHint: $strings.introSemanticNavigate,
|
||||||
onTap: _isOnLastPage ? null : _handleNavTextDoubleTapped,
|
onTap: _isOnLastPage ? null : _handleNavTextSemanticTap,
|
||||||
child: Text($strings.introSemanticSwipeLeft, style: $styles.text.bodySmall),
|
child: Text($strings.introSemanticSwipeLeft, style: $styles.text.bodySmall),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
name: wonders
|
name: wonders
|
||||||
description: Explore the famous wonders of the world.
|
description: Explore the famous wonders of the world.
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
version: 2.0.16+5
|
version: 2.0.17+6
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.17.0 <3.0.0"
|
sdk: ">=2.17.0 <3.0.0"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user