Skip to content

Commit fd9d876

Browse files
committed
Add support for custom backgrounded refresh time
Allow overriding the backgrounded refresh time on `ManUpWidget`
1 parent ff692de commit fd9d876

File tree

5 files changed

+114
-5
lines changed

5 files changed

+114
-5
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# manUp
22

3+
## [9.4.0]
4+
5+
- Allow custom background duration check timeout
6+
37
## [9.3.2]
48

59
- Launch url in external browser

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ Wrap your widget with `ManUpWidget` to automatically handle every thing.
129129
shouldShowAlert: () => true,
130130
onComplete: (bool isComplete) => print(isComplete),
131131
onError: (dynamic e) => print(e.toString()),
132+
checkAfterBackgroundDuration: Duration(minutes: 5), // Optional, only re-check after the app has been in the background for a certain time
132133
child: Container()),
133134
);
134135
}

lib/src/ui/man_up_widget.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ class ManUpWidget extends StatefulWidget {
88
final void Function(dynamic e)? onError;
99
final void Function(ManUpStatus status)? onStatusChanged;
1010

11+
/// After the app has been backgrounded for this duration, check for updates again.
12+
final Duration checkAfterBackgroundDuration;
13+
14+
@visibleForTesting
15+
final DateTime Function() now;
16+
1117
ManUpWidget({
1218
Key? key,
1319
required this.child,
@@ -16,7 +22,10 @@ class ManUpWidget extends StatefulWidget {
1622
this.onComplete,
1723
this.onError,
1824
this.onStatusChanged,
19-
}) : super(key: key);
25+
this.checkAfterBackgroundDuration = Duration.zero,
26+
@visibleForTesting DateTime Function()? now,
27+
}) : now = now ?? DateTime.now,
28+
super(key: key);
2029

2130
@override
2231
_ManUpWidgetState createState() => _ManUpWidgetState();
@@ -30,6 +39,8 @@ class _ManUpWidgetState extends State<ManUpWidget>
3039
WidgetsBindingObserver {
3140
ManUpStatus? alertDialogType;
3241

42+
DateTime? pausedAt;
43+
3344
@override
3445
void initState() {
3546
super.initState();
@@ -85,7 +96,14 @@ class _ManUpWidgetState extends State<ManUpWidget>
8596
@override
8697
void didChangeAppLifecycleState(AppLifecycleState state) {
8798
if (state == AppLifecycleState.resumed) {
88-
validateManUp();
99+
final inBackgroundFor =
100+
pausedAt?.difference(widget.now()).abs() ?? Duration.zero;
101+
if (inBackgroundFor >= widget.checkAfterBackgroundDuration) {
102+
validateManUp();
103+
}
104+
pausedAt = null;
105+
} else if (state == AppLifecycleState.paused) {
106+
pausedAt = widget.now();
89107
}
90108
}
91109

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: manup
22
description: Mandatory update for Flutter Apps that prompts or forces app update by querying a hosted JSON file.
3-
version: 9.3.2
3+
version: 9.4.0
44
homepage: https://github.com/NextFaze/flutter_manup
55

66
environment:

test/man_up_widget_test.dart

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ void main() {
77
const os = 'ios';
88

99
Future<MockManUpService> buildTestCase(WidgetTester tester,
10-
{Metadata? metadata, String? version}) async {
10+
{Metadata? metadata,
11+
String? version,
12+
Duration checkAfterBackgroundDuration = Duration.zero,
13+
DateTime Function()? now}) async {
1114
final manUpService = MockManUpService(
1215
os: os,
1316
packageInfoProvider:
@@ -17,7 +20,12 @@ void main() {
1720
manUpService.metadata = metadata;
1821
}
1922
await tester.pumpWidget(MaterialApp(
20-
home: ManUpWidget(child: Container(), service: manUpService),
23+
home: ManUpWidget(
24+
child: Container(),
25+
service: manUpService,
26+
checkAfterBackgroundDuration: checkAfterBackgroundDuration,
27+
now: now,
28+
),
2129
));
2230
return manUpService;
2331
}
@@ -122,6 +130,77 @@ void main() {
122130
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
123131
await tester.pumpAndSettle();
124132

133+
expect(service.validateCallCount, 2);
134+
expect(find.byType(AlertDialog), findsOneWidget);
135+
expect(
136+
find.text(
137+
'The app is currently in maintenance, please check again shortly.'),
138+
findsOneWidget);
139+
});
140+
141+
testWidgets(
142+
'skips resume re-check when background duration is below custom threshold',
143+
(tester) async {
144+
var now = DateTime(2020, 1, 1, 0, 0, 0);
145+
final service = await buildTestCase(
146+
tester,
147+
checkAfterBackgroundDuration: Duration(minutes: 5),
148+
now: () => now,
149+
);
150+
151+
await tester.pumpAndSettle();
152+
expect(service.validateCallCount, 1);
153+
expect(find.byType(AlertDialog), findsNothing);
154+
155+
service.metadata = Metadata(data: {
156+
os: {
157+
"latest": "2.4.1",
158+
"minimum": "2.1.0",
159+
"url": "http://example.com/myAppUpdate",
160+
"enabled": false
161+
},
162+
});
163+
164+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
165+
await tester.pumpAndSettle();
166+
now = now.add(Duration(minutes: 4));
167+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
168+
await tester.pumpAndSettle();
169+
170+
expect(service.validateCallCount, 1);
171+
expect(find.byType(AlertDialog), findsNothing);
172+
});
173+
174+
testWidgets(
175+
're-checks on resume when background duration meets custom threshold',
176+
(tester) async {
177+
var now = DateTime(2020, 1, 1, 0, 0, 0);
178+
final service = await buildTestCase(
179+
tester,
180+
checkAfterBackgroundDuration: Duration(minutes: 5),
181+
now: () => now,
182+
);
183+
184+
await tester.pumpAndSettle();
185+
expect(service.validateCallCount, 1);
186+
expect(find.byType(AlertDialog), findsNothing);
187+
188+
service.metadata = Metadata(data: {
189+
os: {
190+
"latest": "2.4.1",
191+
"minimum": "2.1.0",
192+
"url": "http://example.com/myAppUpdate",
193+
"enabled": false
194+
},
195+
});
196+
197+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
198+
await tester.pumpAndSettle();
199+
now = now.add(Duration(minutes: 6));
200+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
201+
await tester.pumpAndSettle();
202+
203+
expect(service.validateCallCount, 2);
125204
expect(find.byType(AlertDialog), findsOneWidget);
126205
expect(
127206
find.text(
@@ -188,6 +267,13 @@ class MockManUpService extends ManUpService {
188267
MockManUpService({super.os, super.packageInfoProvider});
189268

190269
Metadata metadata = Metadata(data: {});
270+
int validateCallCount = 0;
271+
272+
@override
273+
Future<ManUpStatus> validate([Metadata? metadata]) {
274+
validateCallCount += 1;
275+
return super.validate(metadata);
276+
}
191277

192278
@override
193279
Future<Metadata> getMetadata() async => metadata;

0 commit comments

Comments
 (0)