Skip to content

Commit f357390

Browse files
committed
example app: add sections and tooltips
1 parent 700d465 commit f357390

10 files changed

+268
-77
lines changed

example/lib/indicators/check_mark_indicator.dart

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:custom_refresh_indicator/custom_refresh_indicator.dart';
2+
import 'package:flutter/foundation.dart';
23
import 'package:flutter/material.dart';
34
import 'package:flutter/rendering.dart';
45

@@ -14,28 +15,41 @@ class CheckMarkColors {
1415

1516
class CheckMarkStyle {
1617
final CheckMarkColors loading;
17-
final CheckMarkColors completed;
18+
final CheckMarkColors success;
19+
final CheckMarkColors error;
1820

1921
const CheckMarkStyle({
2022
required this.loading,
21-
required this.completed,
23+
required this.success,
24+
required this.error,
2225
});
2326

2427
static const defaultStyle = CheckMarkStyle(
25-
loading: CheckMarkColors(content: Colors.white, background: Colors.black),
26-
completed:
27-
CheckMarkColors(content: Colors.white, background: Colors.greenAccent),
28+
loading: CheckMarkColors(
29+
content: Colors.white,
30+
background: Colors.blueAccent,
31+
),
32+
success: CheckMarkColors(
33+
content: Colors.black,
34+
background: Colors.greenAccent,
35+
),
36+
error: CheckMarkColors(
37+
content: Colors.black,
38+
background: Colors.redAccent,
39+
),
2840
);
2941
}
3042

3143
class CheckMarkIndicator extends StatefulWidget {
3244
final Widget child;
3345
final CheckMarkStyle style;
46+
final AsyncCallback onRefresh;
3447

3548
const CheckMarkIndicator({
3649
super.key,
3750
required this.child,
3851
this.style = CheckMarkStyle.defaultStyle,
52+
required this.onRefresh,
3953
});
4054

4155
@override
@@ -49,10 +63,26 @@ class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
4963

5064
ScrollDirection prevScrollDirection = ScrollDirection.idle;
5165

66+
bool _hasError = false;
67+
68+
Future<void> _handleRefresh() async {
69+
try {
70+
setState(() {
71+
_hasError = false;
72+
});
73+
await widget.onRefresh();
74+
} catch (_) {
75+
setState(() {
76+
_hasError = true;
77+
});
78+
rethrow;
79+
}
80+
}
81+
5282
@override
5383
Widget build(BuildContext context) {
5484
return CustomMaterialIndicator(
55-
onRefresh: () => Future.delayed(const Duration(seconds: 2)),
85+
onRefresh: _handleRefresh,
5686
durations: const RefreshIndicatorDurations(
5787
completeDuration: Duration(seconds: 2),
5888
),
@@ -70,9 +100,17 @@ class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
70100
BuildContext context,
71101
IndicatorController controller,
72102
) {
73-
final style = _renderCompleteState
74-
? widget.style.completed
75-
: widget.style.loading;
103+
final CheckMarkColors style;
104+
if (_renderCompleteState) {
105+
if (_hasError) {
106+
style = widget.style.error;
107+
} else {
108+
style = widget.style.success;
109+
}
110+
} else {
111+
style = widget.style.loading;
112+
}
113+
76114
return AnimatedContainer(
77115
duration: const Duration(milliseconds: 150),
78116
alignment: Alignment.center,
@@ -81,9 +119,9 @@ class _CheckMarkIndicatorState extends State<CheckMarkIndicator>
81119
shape: BoxShape.circle,
82120
),
83121
child: _renderCompleteState
84-
? const Icon(
85-
Icons.check,
86-
color: Colors.white,
122+
? Icon(
123+
_hasError ? Icons.close : Icons.check,
124+
color: style.content,
87125
)
88126
: SizedBox(
89127
height: 24,
File renamed without changes.

example/lib/main.dart

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'screens/plane_indicator_screen.dart';
1212
import 'screens/check_mark_indicator_screen.dart';
1313
import 'screens/warp_indicator_screen.dart';
1414
import 'utils/mobile_like_scroll_behavior.dart';
15+
import 'widgets/example_list.dart';
1516

1617
void main() => runApp(const MyApp());
1718

@@ -36,7 +37,8 @@ class MyApp extends StatelessWidget {
3637
'/envelope': (context) => const EnvelopIndicatorScreen(),
3738
'/fetch-more': (context) => const FetchMoreScreen(),
3839
'/horizontal': (context) => const HorizontalScreen(),
39-
'/programmatically-controlled': (context) => const ProgrammaticallyControlled(),
40+
'/programmatically-controlled': (context) =>
41+
const ProgrammaticallyControlled(),
4042
},
4143
);
4244
}
@@ -53,125 +55,126 @@ class MainScreen extends StatelessWidget {
5355
),
5456
body: SafeArea(
5557
child: ListView(
56-
padding: const EdgeInsets.all(15),
58+
padding: const EdgeInsets.all(16),
5759
children: <Widget>[
5860
ElevatedButton(
5961
child: Container(
6062
height: 50,
6163
alignment: Alignment.center,
62-
child: const Text("Controller presentation"),
64+
child: const Text("Overview"),
6365
),
6466
onPressed: () => Navigator.pushNamed(
6567
context,
6668
'/presentation',
6769
),
6870
),
69-
const SizedBox(height: 15),
71+
const SizedBox(height: 16),
7072
ElevatedButton(
7173
child: Container(
7274
height: 50,
7375
alignment: Alignment.center,
74-
child: const Text("Multidirectional Indicator"),
76+
child: const Text("Custom Material Indicator"),
7577
),
7678
onPressed: () => Navigator.pushNamed(
7779
context,
78-
'/horizontal',
80+
'/example',
7981
),
8082
),
81-
const SizedBox(height: 15),
83+
const ListSection(label: "Use cases"),
84+
const SizedBox(height: 16),
8285
ElevatedButton(
8386
child: Container(
8487
height: 50,
8588
alignment: Alignment.center,
86-
child: const Text("Custom Material Indicator"),
89+
child: const Text("Multidirectional"),
8790
),
8891
onPressed: () => Navigator.pushNamed(
8992
context,
90-
'/example',
93+
'/horizontal',
9194
),
9295
),
93-
const SizedBox(height: 15),
96+
const SizedBox(height: 16),
9497
ElevatedButton(
9598
child: Container(
9699
height: 50,
97100
alignment: Alignment.center,
98-
child: const Text("Plane"),
101+
child: const Text("Complete state"),
99102
),
100103
onPressed: () => Navigator.pushNamed(
101104
context,
102-
'/plane',
105+
'/check-mark',
103106
),
104107
),
105-
const SizedBox(height: 15),
108+
const SizedBox(height: 16),
106109
ElevatedButton(
107110
child: Container(
108111
height: 50,
109112
alignment: Alignment.center,
110-
child: const Text("Ice cream"),
113+
child: const Text("Programmatically-controlled"),
111114
),
112115
onPressed: () => Navigator.pushNamed(
113116
context,
114-
'/ice-cream',
117+
'/programmatically-controlled',
115118
),
116119
),
117-
const SizedBox(height: 15),
120+
const ListSection(label: "Indicator examples"),
118121
ElevatedButton(
119122
child: Container(
120123
height: 50,
121124
alignment: Alignment.center,
122-
child: const Text("Witch complete state"),
125+
child: const Text("Pull up to fetch more"),
123126
),
124127
onPressed: () => Navigator.pushNamed(
125128
context,
126-
'/check-mark',
129+
'/fetch-more',
127130
),
128131
),
129-
const SizedBox(height: 15),
132+
const SizedBox(height: 16),
130133
ElevatedButton(
131134
child: Container(
132135
height: 50,
133136
alignment: Alignment.center,
134-
child: const Text("Warp indicator"),
137+
child: const Text("Plane"),
135138
),
136139
onPressed: () => Navigator.pushNamed(
137140
context,
138-
'/warp',
141+
'/plane',
139142
),
140143
),
141-
const SizedBox(height: 15),
144+
const SizedBox(height: 16),
142145
ElevatedButton(
143146
child: Container(
144147
height: 50,
145148
alignment: Alignment.center,
146-
child: const Text("Envelope indicator"),
149+
child: const Text("Ice cream"),
147150
),
148151
onPressed: () => Navigator.pushNamed(
149152
context,
150-
'/envelope',
153+
'/ice-cream',
151154
),
152155
),
153-
const SizedBox(height: 15),
156+
const SizedBox(height: 16),
154157
ElevatedButton(
155158
child: Container(
156159
height: 50,
157160
alignment: Alignment.center,
158-
child: const Text("Programmatically-controlled warp"),
161+
child: const Text("Warp indicator"),
159162
),
160163
onPressed: () => Navigator.pushNamed(
161164
context,
162-
'/programmatically-controlled',
165+
'/warp',
163166
),
164167
),
165-
const SizedBox(height: 15),
168+
const SizedBox(height: 16),
166169
ElevatedButton(
167170
child: Container(
168171
height: 50,
169172
alignment: Alignment.center,
170-
child: const Text("Swipe to fetch more"),
173+
child: const Text("Envelope indicator"),
171174
),
172175
onPressed: () => Navigator.pushNamed(
173176
context,
174-
'/fetch-more',
177+
'/envelope',
175178
),
176179
),
177180
],

example/lib/screens/check_mark_indicator_screen.dart

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,54 @@ class CheckMarkIndicatorScreen extends StatefulWidget {
1212
}
1313

1414
class _CheckMarkIndicatorScreenState extends State<CheckMarkIndicatorScreen> {
15+
bool _useError = false;
1516
@override
1617
Widget build(BuildContext context) {
17-
return const Scaffold(
18-
appBar: ExampleAppBar(),
18+
return Scaffold(
19+
appBar: const ExampleAppBar(
20+
title: "Complete state",
21+
),
1922
body: SafeArea(
2023
child: CheckMarkIndicator(
21-
child: ExampleList(),
24+
onRefresh: () async {
25+
await Future.delayed(const Duration(seconds: 2));
26+
if (_useError) {
27+
throw Exception("Fake exception");
28+
}
29+
},
30+
child: ExampleList(
31+
leading: Column(
32+
children: [
33+
const ListHelpBox(
34+
child: Text(
35+
'You can specify the "complete state" duration to enable the additional state of the indicator widget.',
36+
),
37+
),
38+
const ListHelpBox(
39+
margin: EdgeInsets.fromLTRB(16, 0, 16, 16),
40+
child: Text(
41+
'To configure it, please check the durations parameter of the CustomRefreshIndicator widget.',
42+
),
43+
),
44+
ListHelpBox(
45+
margin: const EdgeInsets.fromLTRB(16, 0, 16, 16),
46+
child: SwitchListTile(
47+
contentPadding: EdgeInsets.zero,
48+
title: Text(
49+
"Simulate unsuccessful fetches",
50+
style: Theme.of(context).textTheme.bodyMedium,
51+
),
52+
value: _useError,
53+
onChanged: (useError) {
54+
setState(() {
55+
_useError = useError;
56+
});
57+
},
58+
),
59+
),
60+
],
61+
),
62+
),
2263
),
2364
),
2465
);

example/lib/screens/custom_material_indicator_screen.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,22 @@ class _CustomMaterialIndicatorScreenState
2929
@override
3030
Widget build(BuildContext context) {
3131
final child = ExampleList(
32+
leading: const Column(
33+
children: [
34+
ListHelpBox(
35+
child: Text(
36+
"Use the toggle on the app bar to change between CustomMaterialIndicator "
37+
"and the built-in RefreshIndicator widget.",
38+
),
39+
),
40+
ListHelpBox(
41+
margin: EdgeInsets.fromLTRB(16, 0, 16, 16),
42+
child: Text(
43+
"Can you spot the difference? 😉",
44+
),
45+
),
46+
],
47+
),
3248
itemCount: 12,
3349
physics: AlwaysScrollableScrollPhysics(
3450
parent: _useCustom

example/lib/screens/fetch_more_screen.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import 'package:example/indicators/swipe_action.dart';
1+
import 'package:example/indicators/fetch_more_indicator.dart';
22
import 'package:example/widgets/example_app_bar.dart';
33
import 'package:example/widgets/example_list.dart';
44
import 'package:flutter/material.dart';
@@ -27,10 +27,16 @@ class _FetchMoreScreenState extends State<FetchMoreScreen> {
2727
@override
2828
Widget build(BuildContext context) {
2929
return Scaffold(
30-
appBar: const ExampleAppBar(title: "Scroll to fetch more"),
30+
appBar: const ExampleAppBar(title: "Pull to fetch more"),
3131
body: FetchMoreIndicator(
3232
onAction: _fetchMore,
3333
child: ExampleList(
34+
leading: const ListHelpBox(
35+
child: Text(
36+
"Scroll to the end of the list "
37+
"and pull up to retrieve more rows.",
38+
),
39+
),
3440
itemCount: _itemsCount,
3541
countElements: true,
3642
),

0 commit comments

Comments
 (0)