Skip to content

Commit 3265356

Browse files
gonuitKamil Klyta
andauthored
Release/v2.0.0 (#36)
* Remove deprecated members and update dependencies * Add the IndicatorSide enum and extension with getters * Add missing getters for the IndicatorState enum For consistency * Make use of IndicatorState getters in the controller * Rename local "_refreshEnabled" field to "_isRefreshEnabled" to be consistency with the public getter. * Add the side property * Refactor * Update changelog * Introduce IndicatorSide class * Update changelog * Move positioned_indicator_container to the example app as it is not the core functionality provided by this package * Update changelog * Remove debug prints * Remove unused import * Both sides * fix test * Rename edge parameter to trigger * Format code * Add trigger mode support * Update docs * update changelog * update changelog * Disable trigger from fake events * Better error message for the "refresh" method * Match the required extent to armed with the built-in indicator * Update ios example project minimum os version * Start refresh immediately after releasing indicator in the armed state * Fixed a bug causing the onRefresh method not being triggered on the iOS * Bump version * Restructure tests directory * Add widget tests * Add trigger tests * Implement equality operator for indicator state change class * Update changelog * Add tests for on state changed function * Add BouncingPhysics tests * Add missing data tests * bump package version * Update offsetToArmed docs * Add autoRebuild argument * Introduce material delegate * Update docs * Formatting * Update readme * Update indicator controller gif * Update version * Rename start and end edge into leading and trailing * Add material indicator delegate to readme * Documentation * Update version * Set version to dev.6 * Fix tables on pub.dev * Add settling state * Remove simple indicator * Fix pub tables * Release 2.0.0 Co-authored-by: Kamil Klyta <kamil.klyta@htdevelopers.com>
1 parent 97f51d6 commit 3265356

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2943
-908
lines changed

CHANGELOG.md

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,25 @@
1+
## 2.0.0
2+
## Breaking changes
3+
- Added `autoRebuild` flag which is by default set to `true`.
4+
From now on, there is no need to wrap widgets in the builder function with the `AnimatedBuilder` widget, as it will be automatically rebuilt. For optimization purposes, you can use the old behavior by setting the `autoRebuild` argument to false.
5+
- Remove *IndicatorState.hiding* state. Instead introduced *IndicatorState.finalizing* and *IndicatorState.canceling*.
6+
- Splited *IndicatorState.loading* state into two phases: *IndicatorState.settling* and *IndicatorState.loading*.
7+
- Renamed `extentPercentageToArmed` argument to `containerExtentPercentageToArmed` which better describes what it exactly does.
8+
- Changed the default value of the `defaultContainerExtentPercentageToArmed` from `0.20` to `0.1(6)` to match the behavior of the built-in indicator widget.
9+
- Removed deprecated **IndicatorStateHelper** class. Instead use **CustomRefreshIndicator.onStateChanged** method.
10+
- Removed deprecated **leadingGlowVisible** and **trailingGlowVisible** arguments. Instead use **leadingScrollIndicatorVisible** and **trailingScrollIndicatorVisible** accoringly.
11+
- Allow setting the edge of the list that will trigger the pull to refresh action.
12+
- Introduced **IndicatorEdge**, **IndicatorTrigger**, **IndicatorSide** and **IndicatorTriggerMode** classes.
13+
- Replaced **reversed** argument of the **CustomRefreshIndicator** class with **trigger**.
14+
- Added **edge** and **side** properties to the **IndicatorController** class.
15+
- Added extension with utility getters for **IndicatorState** class.
16+
- Trigger mode support added. Equivalent to trigger mode of the built-in **RefreshIndicator** widget.
17+
- The **PositionedIndicatorContainer** class is no longer exported from this package, however the source code is available in the example application.
18+
- Now the *onRefresh* function will be triggered immediately when the indicator is released in the armed state. Previously, the *onRefresh* function was triggered when the indicator reached a target value in the loading state of `1.0`.
19+
- Fixed a bug causing the *onRefresh* method not to be triggered on the iOS platform due to bounce physics.
20+
- Implemented equality operator for *IndicatorStateChange* class.
21+
- Improved code coverage with tests
22+
- Multiple minor fixes, improvements and optimizations.
123
## 1.2.1
224
- Flutter 3.0.0 migration backward compatibility fix ([#31](https://github.com/gonuit/flutter-custom-refresh-indicator/pull/31)) by [Jordan1122](https://github.com/Jordan1122)
325
## 1.2.0
@@ -70,12 +92,10 @@
7092

7193
## BREAKING API CHANGES
7294

73-
- Feedback improvements (thank you for your emails!):
74-
- Changed long identifier names:
75-
- `CustomRefreshIndicatorData` => `IndicatorController`
76-
- `CustomRefreshIndicatorState` => `IndicatorState`
77-
- Update example app
78-
- ## `indicatorBuilder` argument is no longer present. Instead use `builder` argument which has some significant changes.
95+
- Changed long identifier names:
96+
- `CustomRefreshIndicatorData` => `IndicatorController`
97+
- `CustomRefreshIndicatorState` => `IndicatorState`
98+
- `indicatorBuilder` argument is no longer present. Instead use `builder` argument which has some significant changes.
7999

80100
To animate indicator based on `IndicatorControler` you can use `AnimationBuilder` widget and pass `IndicatorData` object as `animation` argument. Because of that you can implement your own widget rebuild system what can improve your custom indicator performance (instead of building indicator eg. 300 times you can decide when you want to do it). Example:
81101

@@ -88,9 +108,9 @@ return CustomRefreshIndicator(
88108
/// to child argument
89109
Widget child,
90110
/// Now all your data will be stored in controller.
91-
/// To get controller outside of this function
92-
/// 1. Create controller in parent widget and pass it to CustomRefreshIndicator
93-
/// 2. Assign [GlobalKey] to CustomRefreshIndicator and access `key.currentState.controller`.
111+
/// To get controller outside of this function you can either:
112+
/// - Create controller in parent widget and pass it to CustomRefreshIndicator widget
113+
/// - Assign [GlobalKey] to CustomRefreshIndicator and access `key.currentState.controller`.
94114
IndicatorController controller
95115
) {
96116
return AnimatedBuilder(

README.md

Lines changed: 192 additions & 40 deletions
Large diffs are not rendered by default.

example/.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
/build/
3333

3434
# Web related
35-
lib/generated_plugin_registrant.dart
3635

3736
# Symbolication related
3837
app.*.symbols

example/ios/Flutter/AppFrameworkInfo.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
<key>CFBundleVersion</key>
2222
<string>1.0</string>
2323
<key>MinimumOSVersion</key>
24-
<string>9.0</string>
24+
<string>11.0</string>
2525
</dict>
2626
</plist>

example/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@
272272
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
273273
GCC_WARN_UNUSED_FUNCTION = YES;
274274
GCC_WARN_UNUSED_VARIABLE = YES;
275-
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
275+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
276276
MTL_ENABLE_DEBUG_INFO = NO;
277277
SDKROOT = iphoneos;
278278
SUPPORTED_PLATFORMS = iphoneos;
@@ -350,7 +350,7 @@
350350
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
351351
GCC_WARN_UNUSED_FUNCTION = YES;
352352
GCC_WARN_UNUSED_VARIABLE = YES;
353-
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
353+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
354354
MTL_ENABLE_DEBUG_INFO = YES;
355355
ONLY_ACTIVE_ARCH = YES;
356356
SDKROOT = iphoneos;
@@ -399,7 +399,7 @@
399399
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
400400
GCC_WARN_UNUSED_FUNCTION = YES;
401401
GCC_WARN_UNUSED_VARIABLE = YES;
402-
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
402+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
403403
MTL_ENABLE_DEBUG_INFO = NO;
404404
SDKROOT = iphoneos;
405405
SUPPORTED_PLATFORMS = iphoneos;

example/ios/Runner/Info.plist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@
4343
</array>
4444
<key>UIViewControllerBasedStatusBarAppearance</key>
4545
<false/>
46+
<key>CADisableMinimumFrameDurationOnPhone</key>
47+
<true/>
4648
</dict>
4749
</plist>

example/lib/indicators/envelope_indicator.dart

Lines changed: 80 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class EnvelopRefreshIndicator extends StatelessWidget {
1919
required this.child,
2020
required this.onRefresh,
2121
this.leadingScrollIndicatorVisible = false,
22-
this.trailingScrollIndicatorVisible = true,
22+
this.trailingScrollIndicatorVisible = false,
2323
this.accent,
2424
}) : super(key: key);
2525

@@ -30,97 +30,92 @@ class EnvelopRefreshIndicator extends StatelessWidget {
3030
trailingScrollIndicatorVisible: trailingScrollIndicatorVisible,
3131
builder: (context, child, controller) =>
3232
LayoutBuilder(builder: (context, constraints) {
33-
return AnimatedBuilder(
34-
animation: controller,
35-
builder: (context, _) {
36-
final widgetWidth = constraints.maxWidth;
37-
final widgetHeight = constraints.maxHeight;
38-
final letterTopWidth = (widgetWidth / 2) + 50;
33+
final widgetWidth = constraints.maxWidth;
34+
final widgetHeight = constraints.maxHeight;
35+
final letterTopWidth = (widgetWidth / 2) + 50;
3936

40-
final leftValue =
41-
(widgetWidth - (letterTopWidth * controller.value / 1))
42-
.clamp(letterTopWidth - 100, double.infinity);
37+
final leftValue =
38+
(widgetWidth - (letterTopWidth * controller.value / 1))
39+
.clamp(letterTopWidth - 100, double.infinity);
4340

44-
final rightValue =
45-
(widgetWidth - (widgetWidth * controller.value / 1))
46-
.clamp(0.0, double.infinity);
41+
final rightValue = (widgetWidth - (widgetWidth * controller.value / 1))
42+
.clamp(0.0, double.infinity);
4743

48-
final opacity = (controller.value - 1).clamp(0, 0.5) / 0.5;
49-
return Stack(
50-
children: <Widget>[
51-
Transform.scale(
52-
scale: 1 - 0.1 * controller.value.clamp(0.0, 1.0),
53-
child: child,
54-
),
55-
Positioned(
56-
right: rightValue,
57-
child: Container(
58-
height: widgetHeight,
59-
width: widgetWidth,
60-
decoration: const BoxDecoration(
61-
color: Colors.white,
62-
boxShadow: _defaultShadow,
63-
),
64-
),
65-
),
66-
Positioned(
67-
left: leftValue,
68-
child: CustomPaint(
69-
painter: TrianglePainter(
70-
strokeColor: Colors.white,
71-
paintingStyle: PaintingStyle.fill,
72-
),
73-
child: SizedBox(
74-
height: widgetHeight,
75-
width: letterTopWidth,
76-
),
77-
),
78-
),
79-
if (controller.value >= 1)
80-
Container(
81-
padding: const EdgeInsets.only(right: 100),
82-
child: Transform.scale(
83-
scale: controller.value,
84-
child: Opacity(
85-
opacity: controller.isLoading ? 1 : opacity,
86-
child: Align(
87-
alignment: Alignment.center,
88-
child: Container(
89-
width: _circleSize,
90-
height: _circleSize,
91-
decoration: BoxDecoration(
92-
boxShadow: _defaultShadow,
93-
color: accent ??
94-
Theme.of(context).colorScheme.primary,
95-
shape: BoxShape.circle,
96-
),
97-
child: Stack(
98-
alignment: Alignment.center,
99-
children: <Widget>[
100-
SizedBox(
101-
height: double.infinity,
102-
width: double.infinity,
103-
child: CircularProgressIndicator(
104-
valueColor: const AlwaysStoppedAnimation(
105-
Colors.black),
106-
value: controller.isLoading ? null : 0,
107-
),
108-
),
109-
const Icon(
110-
Icons.mail_outline,
111-
color: Colors.white,
112-
size: 35,
113-
),
114-
],
44+
final opacity = (controller.value - 1).clamp(0, 0.5) / 0.5;
45+
return Stack(
46+
children: <Widget>[
47+
Transform.scale(
48+
scale: 1 - 0.1 * controller.value.clamp(0.0, 1.0),
49+
child: child,
50+
),
51+
Positioned(
52+
right: rightValue,
53+
child: Container(
54+
height: widgetHeight,
55+
width: widgetWidth,
56+
decoration: const BoxDecoration(
57+
color: Colors.white,
58+
boxShadow: _defaultShadow,
59+
),
60+
),
61+
),
62+
Positioned(
63+
left: leftValue,
64+
child: CustomPaint(
65+
painter: TrianglePainter(
66+
strokeColor: Colors.white,
67+
paintingStyle: PaintingStyle.fill,
68+
),
69+
child: SizedBox(
70+
height: widgetHeight,
71+
width: letterTopWidth,
72+
),
73+
),
74+
),
75+
if (controller.value >= 1)
76+
Container(
77+
padding: const EdgeInsets.only(right: 100),
78+
child: Transform.scale(
79+
scale: controller.value,
80+
child: Opacity(
81+
opacity: controller.isLoading ? 1 : opacity,
82+
child: Align(
83+
alignment: Alignment.center,
84+
child: Container(
85+
width: _circleSize,
86+
height: _circleSize,
87+
decoration: BoxDecoration(
88+
boxShadow: _defaultShadow,
89+
color:
90+
accent ?? Theme.of(context).colorScheme.primary,
91+
shape: BoxShape.circle,
92+
),
93+
child: Stack(
94+
alignment: Alignment.center,
95+
children: <Widget>[
96+
SizedBox(
97+
height: double.infinity,
98+
width: double.infinity,
99+
child: CircularProgressIndicator(
100+
valueColor:
101+
const AlwaysStoppedAnimation(Colors.black),
102+
value: controller.isLoading ? null : 0,
115103
),
116104
),
117-
),
105+
const Icon(
106+
Icons.mail_outline,
107+
color: Colors.white,
108+
size: 35,
109+
),
110+
],
118111
),
119112
),
120-
)
121-
],
122-
);
123-
});
113+
),
114+
),
115+
),
116+
)
117+
],
118+
);
124119
}),
125120
child: child,
126121
onRefresh: () => Future<void>.delayed(const Duration(seconds: 2)),

example/lib/indicators/ice_cream_indicator.dart

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@ class _IceCreamIndicatorState extends State<IceCreamIndicator>
5959
static const _indicatorSize = 150.0;
6060
static const _imageSize = 140.0;
6161

62-
IndicatorState? _prevState;
6362
late AnimationController _spoonController;
6463
static final _spoonTween = CurveTween(curve: Curves.easeInOut);
6564

@@ -93,7 +92,17 @@ class _IceCreamIndicatorState extends State<IceCreamIndicator>
9392
return CustomRefreshIndicator(
9493
offsetToArmed: _indicatorSize,
9594
onRefresh: () => Future.delayed(const Duration(seconds: 4)),
95+
autoRebuild: false,
9696
child: widget.child,
97+
onStateChanged: (change) {
98+
if (change.didChange(to: IndicatorState.loading)) {
99+
_spoonController.repeat(reverse: true);
100+
} else if (change.didChange(from: IndicatorState.loading)) {
101+
_spoonController.stop();
102+
} else if (change.didChange(to: IndicatorState.idle)) {
103+
_spoonController.value = 0.0;
104+
}
105+
},
97106
builder: (
98107
BuildContext context,
99108
Widget child,
@@ -104,19 +113,6 @@ class _IceCreamIndicatorState extends State<IceCreamIndicator>
104113
AnimatedBuilder(
105114
animation: controller,
106115
builder: (BuildContext context, Widget? _) {
107-
final currentState = controller.state;
108-
if (_prevState == IndicatorState.armed &&
109-
currentState == IndicatorState.loading) {
110-
_spoonController.repeat(reverse: true);
111-
} else if (_prevState == IndicatorState.loading &&
112-
_prevState != currentState) {
113-
_spoonController.stop();
114-
} else if (currentState == IndicatorState.idle &&
115-
_prevState != currentState) {
116-
_spoonController.value = 0.0;
117-
}
118-
119-
_prevState = currentState;
120116
return SizedBox(
121117
height: controller.value * _indicatorSize,
122118
child: Stack(

0 commit comments

Comments
 (0)