Skip to content

Commit cc227d4

Browse files
yadaniyilclaude
andauthored
feat!: modernize library to v2.0.0
* feat!: modernize library to v2.0.0 with breaking API cleanup - BREAKING: onChanged signature changed from Function({bool changed}) to ValueChanged<bool> for idiomatic Flutter usage - Bump flutter_svg ^2.0.7 -> ^2.2.3, mocktail ^0.3.0 -> ^1.0.4, flutter_lints ^2.0.0 -> ^6.0.0 - Raise SDK floor: Flutter >=3.27.0, Dart >=3.4.0 - Fix: add super.key, const Colors, private state fields, remove double-animation flash in initState, move onChanged call outside setState - Replace empty test suite with 11 widget tests - Add min_coverage: 70 to CI workflow https://claude.ai/code/session_01TR448dBnMeBSf6cHZfpCD2 * docs: update README for v2.0.0 breaking API change - Update install version to ^2.0.0 - Fix onChanged signature in basic and advanced examples - Add migration guide for v1.x -> v2.0.0 https://claude.ai/code/session_01TR448dBnMeBSf6cHZfpCD2 * docs: remove migration guide and breaking change notes No active users — no need for backward compat messaging. https://claude.ai/code/session_01TR448dBnMeBSf6cHZfpCD2 * fix: add Yako to cspell allowlist https://claude.ai/code/session_01TR448dBnMeBSf6cHZfpCD2 * ci: add automated pub.dev publish workflow on version tags Uses OIDC (no secrets required). Triggers on tags matching v*.*.*. https://claude.ai/code/session_01TR448dBnMeBSf6cHZfpCD2 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 6012753 commit cc227d4

8 files changed

Lines changed: 343 additions & 75 deletions

File tree

.github/cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
],
1717
"useGitignore": true,
1818
"words": [
19-
"yako_theme_switch"
19+
"yako_theme_switch",
20+
"Yako"
2021
]
2122
}

.github/workflows/main.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ jobs:
2323
uses: VeryGoodOpenSource/very_good_workflows/.github/workflows/flutter_package.yml@v1
2424
with:
2525
flutter_channel: stable
26+
min_coverage: 70

.github/workflows/publish.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name: publish
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v[0-9]+.[0-9]+.[0-9]+'
7+
8+
jobs:
9+
publish:
10+
permissions:
11+
id-token: write # Required for OIDC publishing to pub.dev
12+
uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1

CHANGELOG.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,26 @@
1+
## [2.0.0] - [Apr 9, 2026]
2+
3+
### Improvements
4+
* Added `super.key` to constructor — widgets can now be identified by key.
5+
* State class fields are now private (`_animationController`, `_turnState`, etc.).
6+
* `createState` uses `State<YakoThemeSwitch>` return type annotation.
7+
* `const Color(...)` used for default color literals.
8+
* Removed redundant `addPostFrameCallback` animation trigger in `initState` — eliminates a visual flash on initial render.
9+
* `onChanged` callback is now called outside `setState`, following Flutter best practices.
10+
* Replaced bare `Container` with `SizedBox` for the toggle hit area (semantic clarity).
11+
12+
### Dependency Updates
13+
* `flutter_svg` bumped from `^2.0.7` to `^2.2.3`
14+
* `mocktail` bumped from `^0.3.0` to `^1.0.4`
15+
* `flutter_lints` bumped from `^2.0.0` to `^6.0.0`
16+
* Minimum Flutter SDK raised from `>=3.10.0` to `>=3.27.0`
17+
* Minimum Dart SDK raised from `>=3.0.0` to `>=3.4.0`
18+
19+
### Tests
20+
* Replaced empty/commented test suite with 11 widget tests covering:
21+
rendering, default state, enabled state, tap callbacks, external prop
22+
updates, custom width, custom colors, custom duration, border radius,
23+
key support, and multi-tap alternation.
24+
125
## [1.0.0+1] - [Jul 9, 2023]
226
* First release

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,26 @@ Just a cool switch for your app's theme
1111
In your pubspec.yaml
1212
```yaml
1313
dependencies:
14-
yako_theme_switch: ^1.0.0
14+
yako_theme_switch: ^2.0.0
1515
```
1616
<br>
1717
1818
## Basic Usage:
1919
```dart
2020
YakoThemeSwitch(
2121
enabled: themeMode == ThemeMode.light,
22-
onChanged: ({bool? changed}) {},
22+
onChanged: (bool value) {
23+
setState(() => themeMode = value ? ThemeMode.light : ThemeMode.dark);
24+
},
2325
);
2426
```
2527
## Advanced usage
2628
```dart
2729
YakoThemeSwitch(
2830
enabled: themeMode == ThemeMode.light,
29-
onChanged: ({bool? changed}) {},
31+
onChanged: (bool value) {
32+
setState(() => themeMode = value ? ThemeMode.light : ThemeMode.dark);
33+
},
3034
width: 50,
3135
enabledBackgroundColor: Colors.blue,
3236
disabledBackgroundColor: Colors.red,

lib/src/yako_theme_switch.dart

Lines changed: 57 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ class YakoThemeSwitch extends StatefulWidget {
88
/// You can set the custom width of the switch
99
final double width;
1010

11-
/// Just a callback function to get the changed state of the switch
12-
final Function({bool changed}) onChanged;
11+
/// Callback invoked with the new state whenever the switch is toggled
12+
final ValueChanged<bool> onChanged;
1313

1414
/// The background color of the switch when it is enabled
1515
final Color? enabledBackgroundColor;
@@ -26,10 +26,11 @@ class YakoThemeSwitch extends StatefulWidget {
2626
/// The duration of the animation
2727
final Duration animationDuration;
2828

29-
/// The border radius of the toggle. Try setting it to 4 and chech how circle now is square
29+
/// The border radius of the toggle. Try setting it to 4 to make the circle square
3030
final double? enabledToggleBorderRadius;
3131

3232
const YakoThemeSwitch({
33+
super.key,
3334
this.enabled = false,
3435
this.width = 45,
3536
this.enabledBackgroundColor,
@@ -42,61 +43,57 @@ class YakoThemeSwitch extends StatefulWidget {
4243
});
4344

4445
@override
45-
_YakoThemeSwitchState createState() => _YakoThemeSwitchState();
46+
State<YakoThemeSwitch> createState() => _YakoThemeSwitchState();
4647
}
4748

4849
class _YakoThemeSwitchState extends State<YakoThemeSwitch>
4950
with SingleTickerProviderStateMixin {
50-
late AnimationController animationController;
51-
late Animation<double> animation;
52-
late bool turnState;
53-
late Color enabledBackgroundColor;
54-
late Color disabledBackgroundColor;
55-
late Color enabledToggleColor;
56-
late Color disabledToggleColor;
57-
double animationControllerValue = 0.0;
51+
late AnimationController _animationController;
52+
late Animation<double> _animation;
53+
late bool _turnState;
54+
late Color _enabledBackgroundColor;
55+
late Color _disabledBackgroundColor;
56+
late Color _enabledToggleColor;
57+
late Color _disabledToggleColor;
58+
double _animationValue = 0.0;
5859

5960
@override
6061
void dispose() {
61-
animationController.dispose();
62+
_animationController.dispose();
6263
super.dispose();
6364
}
6465

6566
@override
6667
void initState() {
6768
super.initState();
6869

69-
enabledBackgroundColor =
70+
_enabledBackgroundColor =
7071
widget.enabledBackgroundColor ?? Colors.grey.shade300;
71-
disabledBackgroundColor =
72-
widget.disabledBackgroundColor ?? Color(0xFF2E386E);
73-
enabledToggleColor =
72+
_disabledBackgroundColor =
73+
widget.disabledBackgroundColor ?? const Color(0xFF2E386E);
74+
_enabledToggleColor =
7475
widget.enabledToggleColor ?? Colors.amberAccent.shade700;
75-
disabledToggleColor = widget.disabledToggleColor ?? Color(0xFF70E2FB);
76+
_disabledToggleColor =
77+
widget.disabledToggleColor ?? const Color(0xFF70E2FB);
7678

77-
animationControllerValue = widget.enabled ? 1.0 : 0.0;
78-
animationController = AnimationController(
79-
value: animationControllerValue,
79+
_turnState = widget.enabled;
80+
_animationValue = widget.enabled ? 1.0 : 0.0;
81+
82+
_animationController = AnimationController(
83+
value: _animationValue,
8084
vsync: this,
8185
lowerBound: 0.0,
8286
upperBound: 1.0,
8387
duration: widget.animationDuration,
8488
);
85-
animation =
86-
CurvedAnimation(parent: animationController, curve: Curves.easeInOut);
87-
88-
animationController.addListener(() {
89-
setState(() {
90-
animationControllerValue = animation.value;
91-
});
92-
});
93-
turnState = widget.enabled;
89+
_animation = CurvedAnimation(
90+
parent: _animationController,
91+
curve: Curves.easeInOut,
92+
);
9493

95-
WidgetsBinding.instance.addPostFrameCallback((_) {
94+
_animationController.addListener(() {
9695
setState(() {
97-
if (turnState) {
98-
animationController.forward();
99-
}
96+
_animationValue = _animation.value;
10097
});
10198
});
10299
}
@@ -105,29 +102,26 @@ class _YakoThemeSwitchState extends State<YakoThemeSwitch>
105102
void didUpdateWidget(YakoThemeSwitch oldWidget) {
106103
super.didUpdateWidget(oldWidget);
107104

108-
// if enabled value is updated, reflect the change in switch
109105
if (oldWidget.enabled != widget.enabled) {
110-
turnState = widget.enabled;
111-
if (turnState) {
112-
animationController.forward();
106+
_turnState = widget.enabled;
107+
if (_turnState) {
108+
_animationController.forward();
113109
} else {
114-
animationController.reverse();
110+
_animationController.reverse();
115111
}
116112
}
117113
}
118114

119115
@override
120116
Widget build(BuildContext context) {
121117
final Color? transitionColor = Color.lerp(
122-
disabledBackgroundColor,
123-
enabledBackgroundColor,
124-
animationControllerValue,
118+
_disabledBackgroundColor,
119+
_enabledBackgroundColor,
120+
_animationValue,
125121
);
126122

127123
return GestureDetector(
128-
onTap: () {
129-
toggle(changeState: true);
130-
},
124+
onTap: _toggle,
131125
child: Container(
132126
padding: const EdgeInsets.all(3),
133127
width: widget.width,
@@ -138,23 +132,21 @@ class _YakoThemeSwitchState extends State<YakoThemeSwitch>
138132
child: Stack(
139133
children: <Widget>[
140134
Transform.translate(
141-
offset: Offset((widget.width - 25) * animationControllerValue, 0),
135+
offset: Offset((widget.width - 25) * _animationValue, 0),
142136
child: Transform.rotate(
143-
angle: animationControllerValue,
144-
child: Container(
137+
angle: _animationValue,
138+
child: SizedBox(
145139
height: 18,
146140
width: 18,
147-
alignment: Alignment.center,
148141
child: Stack(
149142
children: <Widget>[
150143
Center(
151144
child: Opacity(
152-
opacity:
153-
(1 - animationControllerValue).clamp(0.0, 1.0),
145+
opacity: (1 - _animationValue).clamp(0.0, 1.0),
154146
child: SvgPicture.asset(
155147
'assets/dark_mode_switch_icon.svg',
156148
colorFilter: ColorFilter.mode(
157-
disabledToggleColor,
149+
_disabledToggleColor,
158150
BlendMode.srcIn,
159151
),
160152
height: 18,
@@ -164,12 +156,13 @@ class _YakoThemeSwitchState extends State<YakoThemeSwitch>
164156
),
165157
Center(
166158
child: Opacity(
167-
opacity: animationControllerValue.clamp(0.0, 1.0),
159+
opacity: _animationValue.clamp(0.0, 1.0),
168160
child: Container(
169161
decoration: BoxDecoration(
170162
borderRadius: BorderRadius.circular(
171-
widget.enabledToggleBorderRadius ?? 20),
172-
color: enabledToggleColor,
163+
widget.enabledToggleBorderRadius ?? 20,
164+
),
165+
color: _enabledToggleColor,
173166
),
174167
),
175168
),
@@ -178,19 +171,22 @@ class _YakoThemeSwitchState extends State<YakoThemeSwitch>
178171
),
179172
),
180173
),
181-
)
174+
),
182175
],
183176
),
184177
),
185178
);
186179
}
187180

188-
void toggle({bool changeState = false}) {
181+
void _toggle() {
189182
setState(() {
190-
if (changeState) turnState = !turnState;
191-
turnState ? animationController.forward() : animationController.reverse();
192-
193-
widget.onChanged(changed: turnState);
183+
_turnState = !_turnState;
184+
if (_turnState) {
185+
_animationController.forward();
186+
} else {
187+
_animationController.reverse();
188+
}
194189
});
190+
widget.onChanged(_turnState);
195191
}
196192
}

pubspec.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: yako_theme_switch
22
description: Custom switch that looks good for changing the theme of the app
3-
version: 1.0.0+1
3+
version: 2.0.0
44
repository: https://github.com/yako-dev/flutter-yako-theme-switch
55
issue_tracker: https://github.com/yako-dev/flutter-yako-theme-switch/issues
66

@@ -12,19 +12,19 @@ screenshots:
1212
path: assets/showcase_animation.gif
1313

1414
environment:
15-
sdk: ">=3.0.0 <4.0.0"
16-
flutter: ">=3.10.0"
15+
sdk: ">=3.4.0 <4.0.0"
16+
flutter: ">=3.27.0"
1717

1818
dependencies:
1919
flutter:
2020
sdk: flutter
21-
flutter_svg: ^2.0.7
21+
flutter_svg: ^2.2.3
2222

2323
dev_dependencies:
2424
flutter_test:
2525
sdk: flutter
26-
mocktail: ^0.3.0
27-
flutter_lints: ^2.0.0
26+
mocktail: ^1.0.4
27+
flutter_lints: ^6.0.0
2828

2929
flutter:
3030
assets:

0 commit comments

Comments
 (0)