@@ -2,6 +2,7 @@ import 'package:app/presentation/navigation/routers.dart';
22import 'package:app/presentation/resources/locale/generated/l10n.dart' ;
33import 'package:app/presentation/resources/resources.dart' ;
44import 'package:flutter/material.dart' ;
5+ import 'package:flutter/services.dart' ;
56
67class OnboardingPage extends StatefulWidget {
78 const OnboardingPage ({super .key});
@@ -12,12 +13,14 @@ class OnboardingPage extends StatefulWidget {
1213
1314class _OnboardingPageState extends State <OnboardingPage > {
1415 final PageController _pageController = PageController ();
16+ final FocusNode _focusNode = FocusNode ();
1517 int _currentPage = 0 ;
1618 final int _totalPages = 4 ;
1719
1820 @override
1921 void dispose () {
2022 _pageController.dispose ();
23+ _focusNode.dispose ();
2124 super .dispose ();
2225 }
2326
@@ -55,95 +58,115 @@ class _OnboardingPageState extends State<OnboardingPage> {
5558 @override
5659 Widget build (BuildContext context) {
5760 return Scaffold (
58- body: SafeArea (
59- child: Column (
60- children: [
61- // Page Indicator
62- Padding (
63- padding: const EdgeInsets .all (Dimen .spacingM),
64- child: Row (
65- mainAxisAlignment: MainAxisAlignment .center,
66- children: List .generate (
67- _totalPages,
68- (index) => Container (
69- margin:
70- const EdgeInsets .symmetric (horizontal: Dimen .spacingXs),
71- width:
72- _currentPage == index ? Dimen .spacingL : Dimen .spacingS,
73- height: Dimen .spacingS,
74- decoration: BoxDecoration (
75- color: _currentPage == index
76- ? Theme .of (context).colorScheme.primary
77- : Theme .of (context).colorScheme.outline,
78- borderRadius: BorderRadius .circular (Dimen .spacingXs),
61+ body: Focus (
62+ focusNode: _focusNode,
63+ autofocus: true ,
64+ onKeyEvent: (node, event) {
65+ if (event is KeyDownEvent ) {
66+ if (event.logicalKey == LogicalKeyboardKey .arrowRight) {
67+ _nextPage ();
68+ return KeyEventResult .handled;
69+ } else if (event.logicalKey == LogicalKeyboardKey .arrowLeft) {
70+ _previousPage ();
71+ return KeyEventResult .handled;
72+ }
73+ }
74+ return KeyEventResult .ignored;
75+ },
76+ child: SafeArea (
77+ child: Column (
78+ children: [
79+ // Page Indicator
80+ Padding (
81+ padding: const EdgeInsets .all (Dimen .spacingM),
82+ child: Semantics (
83+ label: S .of (context).onboardingPageIndicator (
84+ _currentPage + 1 ,
85+ _totalPages,
86+ ),
87+ child: Row (
88+ mainAxisAlignment: MainAxisAlignment .center,
89+ children: List .generate (
90+ _totalPages,
91+ (index) => Container (
92+ margin: const EdgeInsets .symmetric (
93+ horizontal: Dimen .spacingXs),
94+ width: _currentPage == index
95+ ? Dimen .spacingL
96+ : Dimen .spacingS,
97+ height: Dimen .spacingS,
98+ decoration: BoxDecoration (
99+ color: _currentPage == index
100+ ? Theme .of (context).colorScheme.primary
101+ : Theme .of (context).colorScheme.outline,
102+ borderRadius: BorderRadius .circular (Dimen .spacingXs),
103+ ),
104+ ),
79105 ),
80106 ),
81107 ),
82108 ),
83- ),
84-
85- // PageView
86- Expanded (
87- child: PageView (
88- controller: _pageController,
89- onPageChanged: _onPageChanged,
90- children: [
91- _buildPage (
92- title: S .of (context).onboardingPage1Title,
93- description: S .of (context).onboardingPage1Description,
94- icon: Icons .waving_hand,
95- color: Theme .of (context).colorScheme.primary,
96- ),
97- _buildPage (
98- title: S .of (context).onboardingPage2Title,
99- description: S .of (context).onboardingPage2Description,
100- icon: Icons .explore,
101- color: Theme .of (context).colorScheme.secondary,
102- ),
103- _buildPage (
104- title: S .of (context).onboardingPage3Title,
105- description: S .of (context).onboardingPage3Description,
106- icon: Icons .people,
107- color: Theme .of (context).colorScheme.tertiary,
108- ),
109- _buildPage (
110- title: S .of (context).onboardingPage4Title,
111- description: S .of (context).onboardingPage4Description,
112- icon: Icons .rocket_launch,
113- color: Theme .of (context).colorScheme.error,
114- ),
115- ],
109+ // PageView
110+ Expanded (
111+ child: PageView (
112+ controller: _pageController,
113+ onPageChanged: _onPageChanged,
114+ children: [
115+ _buildPage (
116+ title: S .of (context).onboardingPage1Title,
117+ description: S .of (context).onboardingPage1Description,
118+ icon: Icons .waving_hand,
119+ color: Theme .of (context).colorScheme.primary,
120+ ),
121+ _buildPage (
122+ title: S .of (context).onboardingPage2Title,
123+ description: S .of (context).onboardingPage2Description,
124+ icon: Icons .explore,
125+ color: Theme .of (context).colorScheme.secondary,
126+ ),
127+ _buildPage (
128+ title: S .of (context).onboardingPage3Title,
129+ description: S .of (context).onboardingPage3Description,
130+ icon: Icons .people,
131+ color: Theme .of (context).colorScheme.tertiary,
132+ ),
133+ _buildPage (
134+ title: S .of (context).onboardingPage4Title,
135+ description: S .of (context).onboardingPage4Description,
136+ icon: Icons .rocket_launch,
137+ color: Theme .of (context).colorScheme.error,
138+ ),
139+ ],
140+ ),
116141 ),
117- ),
118-
119- // Navigation Buttons
120- Padding (
121- padding: const EdgeInsets .all (Dimen .spacingL),
122- child: Row (
123- mainAxisAlignment: MainAxisAlignment .spaceBetween,
124- children: [
125- // Back Button (hidden on first page)
126- if (_currentPage > 0 )
127- TextButton (
128- onPressed: _previousPage,
129- child: Text (S .of (context).onboardingBack),
130- )
131- else
132- const SizedBox (width: 80 ), // Placeholder for alignment
133-
134- // Next/Start Button
135- ElevatedButton (
136- onPressed: _nextPage,
137- child: Text (
138- _currentPage == _totalPages - 1
139- ? S .of (context).onboardingStart
140- : S .of (context).onboardingNext,
142+ // Navigation Buttons
143+ Padding (
144+ padding: const EdgeInsets .all (Dimen .spacingL),
145+ child: Row (
146+ mainAxisAlignment: MainAxisAlignment .spaceBetween,
147+ children: [
148+ // Back Button (hidden on first page)
149+ if (_currentPage > 0 )
150+ TextButton (
151+ onPressed: _previousPage,
152+ child: Text (S .of (context).onboardingBack),
153+ )
154+ else
155+ const SizedBox (width: Dimen .spacingL),
156+ // Next/Start Button
157+ ElevatedButton (
158+ onPressed: _nextPage,
159+ child: Text (
160+ _currentPage == _totalPages - 1
161+ ? S .of (context).onboardingStart
162+ : S .of (context).onboardingNext,
163+ ),
141164 ),
142- ) ,
143- ] ,
165+ ] ,
166+ ) ,
144167 ),
145- ) ,
146- ] ,
168+ ] ,
169+ ) ,
147170 ),
148171 ),
149172 );
@@ -162,7 +185,7 @@ class _OnboardingPageState extends State<OnboardingPage> {
162185 children: [
163186 Icon (
164187 icon,
165- size: 120 ,
188+ size: Dimen .onboardingIconSize ,
166189 color: color,
167190 ),
168191 const SizedBox (height: Dimen .spacingXl),
0 commit comments