Skip to content

Commit 3c04010

Browse files
committed
v6.27.0
1 parent 2f10023 commit 3c04010

File tree

13 files changed

+1115
-170
lines changed

13 files changed

+1115
-170
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
## [6.27.0] - 2025-04-19
2+
3+
* Small breaking change to `stateActions`:
4+
* Was: `Map<String, Function()> get stateActions`
5+
* Now: `Map<String, Function> get stateActions`
6+
* Added: `JourneyProgressStyle? progressStyle;` to journey widget
7+
* Added: `JourneyButtonStyle? buttonStyle;` to journey widget
8+
* Added: `backgroundGradient` to bottomNav, topNav and journey widget
9+
* Updated: `stateAction` to support new `data` parameter
10+
* New progress styles added to `JourneyProgressStyle` - `linear`, `dots`, `numbered`, `segments`, `circular`, `timeline`, `custom`
11+
* New `JourneyButtonStyle` added to `JourneyState` - `default`, `primary`, `secondary`, `tertiary`
12+
* New `JourneyButtonStyle` added to `JourneyState` - `standard`, `minimal`, `outlined`, `contained`, `custom`
13+
114
## [6.26.0] - 2025-04-16
215

316
* Added: `JourneyState` class to help manage `NavigationHubLayout.journey`

example/pubspec.lock

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,10 @@ packages:
194194
dependency: transitive
195195
description:
196196
name: flutter_local_notifications
197-
sha256: d59eeafd6df92174b1d5f68fc9d66634c97ce2e7cfe2293476236547bb19bbbd
197+
sha256: "33b3e0269ae9d51669957a923f2376bee96299b09915d856395af8c4238aebfa"
198198
url: "https://pub.dev"
199199
source: hosted
200-
version: "19.0.0"
200+
version: "19.1.0"
201201
flutter_local_notifications_linux:
202202
dependency: transitive
203203
description:
@@ -419,7 +419,7 @@ packages:
419419
path: ".."
420420
relative: true
421421
source: path
422-
version: "6.23.0"
422+
version: "6.27.0"
423423
path:
424424
dependency: transitive
425425
description:

lib/helpers/helper.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,8 +392,8 @@ void updateState<T>(dynamic name,
392392

393393
/// Send a state action to a [NyState] or [NyPage] in your application.
394394
/// Provide the [state] and the [action] you want to send.
395-
stateAction(String action, {required dynamic state}) {
396-
updateState(state, data: {"action": action});
395+
stateAction(String action, {required dynamic state, dynamic data}) {
396+
updateState(state, data: {"action": action, "data": data});
397397
}
398398

399399
/// api helper

lib/helpers/state_action.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class StateAction {
1212
return state;
1313
}
1414
if (state is RouteView) {
15-
return state.nyPageName();
15+
return state.stateName();
1616
}
1717
return "";
1818
}
Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
import 'package:flutter/material.dart';
2+
import '/localization/app_localization.dart';
3+
4+
/// A dot-based progress indicator for journeys
5+
class JourneyDotProgress extends StatelessWidget {
6+
final int currentStep;
7+
final int totalSteps;
8+
final Color activeColor;
9+
final Color inactiveColor;
10+
final double dotSize;
11+
final double spacing;
12+
13+
const JourneyDotProgress({
14+
super.key,
15+
required this.currentStep,
16+
required this.totalSteps,
17+
required this.activeColor,
18+
required this.inactiveColor,
19+
this.dotSize = 10.0,
20+
this.spacing = 8.0,
21+
});
22+
23+
@override
24+
Widget build(BuildContext context) {
25+
return Row(
26+
mainAxisAlignment: MainAxisAlignment.center,
27+
children: List.generate(totalSteps, (index) {
28+
final isActive = index <= currentStep;
29+
return Padding(
30+
padding: EdgeInsets.symmetric(horizontal: spacing / 2),
31+
child: AnimatedContainer(
32+
duration: const Duration(milliseconds: 300),
33+
width: isActive ? dotSize * 1.5 : dotSize,
34+
height: dotSize,
35+
decoration: BoxDecoration(
36+
color: isActive ? activeColor : inactiveColor,
37+
borderRadius: BorderRadius.circular(dotSize / 2),
38+
),
39+
),
40+
);
41+
}),
42+
);
43+
}
44+
}
45+
46+
/// A numbered step progress indicator for journeys
47+
class JourneyNumberedProgress extends StatelessWidget {
48+
final int currentStep;
49+
final int totalSteps;
50+
final Color activeColor;
51+
final Color inactiveColor;
52+
final Color textColor;
53+
final double circleSize;
54+
final double spacing;
55+
56+
const JourneyNumberedProgress({
57+
super.key,
58+
required this.currentStep,
59+
required this.totalSteps,
60+
required this.activeColor,
61+
required this.inactiveColor,
62+
required this.textColor,
63+
this.circleSize = 28.0,
64+
this.spacing = 4.0,
65+
});
66+
67+
@override
68+
Widget build(BuildContext context) {
69+
// Limit the number of circles to show to prevent overflow
70+
final maxCirclesToShow = 5;
71+
72+
// If too many steps, show simplified version
73+
if (totalSteps > maxCirclesToShow) {
74+
return Row(
75+
mainAxisAlignment: MainAxisAlignment.center,
76+
children: [
77+
_buildNumberCircle(currentStep),
78+
Padding(
79+
padding: EdgeInsets.symmetric(horizontal: spacing),
80+
child: Text(
81+
'of'.tr(),
82+
style: TextStyle(
83+
color: textColor,
84+
fontWeight: FontWeight.bold,
85+
),
86+
),
87+
),
88+
_buildNumberCircle(totalSteps - 1, isTotal: true),
89+
],
90+
);
91+
}
92+
93+
// Standard display with all step numbers
94+
return Row(
95+
mainAxisAlignment: MainAxisAlignment.center,
96+
children: List.generate(totalSteps, (index) {
97+
// Add connecting line between circles except after the last one
98+
if (index < totalSteps - 1) {
99+
return Row(
100+
children: [
101+
_buildNumberCircle(index),
102+
Container(
103+
width: spacing * 3,
104+
height: 2,
105+
color: index < currentStep ? activeColor : inactiveColor,
106+
),
107+
],
108+
);
109+
} else {
110+
return _buildNumberCircle(index);
111+
}
112+
}),
113+
);
114+
}
115+
116+
Widget _buildNumberCircle(int index, {bool isTotal = false}) {
117+
final isActive = index <= currentStep && !isTotal;
118+
return AnimatedContainer(
119+
duration: const Duration(milliseconds: 300),
120+
width: circleSize,
121+
height: circleSize,
122+
decoration: BoxDecoration(
123+
color: isActive ? activeColor : inactiveColor,
124+
shape: BoxShape.circle,
125+
border: Border.all(
126+
color: isActive ? activeColor : inactiveColor,
127+
width: 2,
128+
),
129+
),
130+
child: Center(
131+
child: Text(
132+
'${index + 1}',
133+
style: TextStyle(
134+
color: isActive ? Colors.white : textColor,
135+
fontWeight: FontWeight.bold,
136+
fontSize: circleSize * 0.4,
137+
),
138+
),
139+
),
140+
);
141+
}
142+
}
143+
144+
/// A segmented progress bar for journeys
145+
class JourneySegmentProgress extends StatelessWidget {
146+
final int currentStep;
147+
final int totalSteps;
148+
final Color activeColor;
149+
final Color inactiveColor;
150+
final double height;
151+
final double spacing;
152+
153+
const JourneySegmentProgress({
154+
super.key,
155+
required this.currentStep,
156+
required this.totalSteps,
157+
required this.activeColor,
158+
required this.inactiveColor,
159+
this.height = 4.0,
160+
this.spacing = 4.0,
161+
});
162+
163+
@override
164+
Widget build(BuildContext context) {
165+
return Row(
166+
children: List.generate(totalSteps, (index) {
167+
final isActive = index <= currentStep;
168+
return Expanded(
169+
child: Padding(
170+
padding: EdgeInsets.symmetric(horizontal: spacing / 2),
171+
child: AnimatedContainer(
172+
duration: const Duration(milliseconds: 300),
173+
height: height,
174+
decoration: BoxDecoration(
175+
color: isActive ? activeColor : inactiveColor,
176+
borderRadius: BorderRadius.circular(height / 2),
177+
),
178+
),
179+
),
180+
);
181+
}),
182+
);
183+
}
184+
}
185+
186+
/// A circular progress indicator for journeys
187+
class JourneyCircularProgress extends StatelessWidget {
188+
final double percentage;
189+
final Color activeColor;
190+
final Color inactiveColor;
191+
final Color textColor;
192+
final double size;
193+
final double thickness;
194+
final bool showPercentage;
195+
196+
const JourneyCircularProgress({
197+
super.key,
198+
required this.percentage,
199+
required this.activeColor,
200+
required this.inactiveColor,
201+
required this.textColor,
202+
this.size = 40.0,
203+
this.thickness = 4.0,
204+
this.showPercentage = true,
205+
});
206+
207+
@override
208+
Widget build(BuildContext context) {
209+
return SizedBox(
210+
width: size,
211+
height: size,
212+
child: Stack(
213+
alignment: Alignment.center,
214+
children: [
215+
CircularProgressIndicator(
216+
value: percentage,
217+
backgroundColor: inactiveColor,
218+
valueColor: AlwaysStoppedAnimation<Color>(activeColor),
219+
strokeWidth: thickness,
220+
),
221+
if (showPercentage)
222+
Text(
223+
'${(percentage * 100).round()}%',
224+
style: TextStyle(
225+
color: textColor,
226+
fontSize: size * 0.3,
227+
fontWeight: FontWeight.bold,
228+
),
229+
),
230+
],
231+
),
232+
);
233+
}
234+
}
235+
236+
/// A timeline-style progress indicator for journeys
237+
class JourneyTimelineProgress extends StatelessWidget {
238+
final int currentStep;
239+
final int totalSteps;
240+
final Color activeColor;
241+
final Color inactiveColor;
242+
final double lineThickness;
243+
final double dotSize;
244+
final bool showLabels;
245+
246+
const JourneyTimelineProgress({
247+
super.key,
248+
required this.currentStep,
249+
required this.totalSteps,
250+
required this.activeColor,
251+
required this.inactiveColor,
252+
this.lineThickness = 2.0,
253+
this.dotSize = 12.0,
254+
this.showLabels = true,
255+
});
256+
257+
@override
258+
Widget build(BuildContext context) {
259+
return SizedBox(
260+
height: showLabels ? 50.0 : 24.0,
261+
child: Row(
262+
children: List.generate(totalSteps * 2 - 1, (index) {
263+
// Even indices are dots, odd indices are connecting lines
264+
if (index % 2 == 0) {
265+
// This is a dot (step indicator)
266+
final stepIndex = index ~/ 2;
267+
final isActive = stepIndex <= currentStep;
268+
final isCurrent = stepIndex == currentStep;
269+
270+
return Column(
271+
mainAxisSize: MainAxisSize.min,
272+
children: [
273+
Container(
274+
width: dotSize,
275+
height: dotSize,
276+
decoration: BoxDecoration(
277+
color: isActive ? activeColor : inactiveColor,
278+
shape: BoxShape.circle,
279+
border: isCurrent
280+
? Border.all(
281+
color: activeColor,
282+
width: 2,
283+
)
284+
: null,
285+
boxShadow: isCurrent
286+
? [
287+
BoxShadow(
288+
color:
289+
activeColor.withAlpha((255.0 * 0.3).round()),
290+
blurRadius: 4,
291+
spreadRadius: 1,
292+
)
293+
]
294+
: null,
295+
),
296+
),
297+
if (showLabels)
298+
Padding(
299+
padding: const EdgeInsets.only(top: 4.0),
300+
child: Text(
301+
'Step ${stepIndex + 1}'.tr(),
302+
style: TextStyle(
303+
color: isActive ? activeColor : inactiveColor,
304+
fontSize: 10,
305+
fontWeight:
306+
isCurrent ? FontWeight.bold : FontWeight.normal,
307+
),
308+
),
309+
),
310+
],
311+
);
312+
} else {
313+
// This is a connecting line
314+
final beforeIndex = index ~/ 2;
315+
final isActive = beforeIndex <= currentStep - 1;
316+
317+
return Expanded(
318+
child: Container(
319+
height: lineThickness,
320+
color: isActive ? activeColor : inactiveColor,
321+
),
322+
);
323+
}
324+
}),
325+
),
326+
);
327+
}
328+
}

0 commit comments

Comments
 (0)