Skip to content

Commit f67e4e0

Browse files
authored
Merge pull request #4 from blendto/fix/app-lifecycle-events
Fix/app lifecycle events
2 parents 8a3909f + 87b070d commit f67e4e0

9 files changed

Lines changed: 146 additions & 6 deletions

File tree

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
name: Version bump check
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened, ready_for_review]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
check-tugboat-version:
12+
name: Require tugboat version bump
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Compare package version to base
21+
env:
22+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
23+
PACKAGE_PUBSPEC: packages/tugboat/pubspec.yaml
24+
run: |
25+
set -euo pipefail
26+
27+
extract_version() {
28+
local file="$1"
29+
if [[ ! -f "$file" ]]; then
30+
echo ""
31+
return
32+
fi
33+
grep -E '^version:' "$file" | head -1 | sed -E 's/^version:[[:space:]]*//' | tr -d '"' | tr -d "'" | tr -d '[:space:]'
34+
}
35+
36+
if [[ ! -f "$PACKAGE_PUBSPEC" ]]; then
37+
echo "::error::$PACKAGE_PUBSPEC is missing on this branch"
38+
exit 1
39+
fi
40+
41+
head_version="$(extract_version "$PACKAGE_PUBSPEC")"
42+
if [[ -z "$head_version" ]]; then
43+
echo "::error::Could not read version from $PACKAGE_PUBSPEC"
44+
exit 1
45+
fi
46+
47+
base_file="$(mktemp)"
48+
if ! git show "${BASE_SHA}:${PACKAGE_PUBSPEC}" >"$base_file" 2>/dev/null; then
49+
echo "Base branch has no $PACKAGE_PUBSPEC; treating as new package (ok)."
50+
echo "PR version: $head_version"
51+
exit 0
52+
fi
53+
54+
base_version="$(extract_version "$base_file")"
55+
rm -f "$base_file"
56+
57+
if [[ -z "$base_version" ]]; then
58+
echo "::error::Could not read version from base $PACKAGE_PUBSPEC"
59+
exit 1
60+
fi
61+
62+
echo "Base version: $base_version"
63+
echo "PR version: $head_version"
64+
65+
if [[ "$head_version" == "$base_version" ]]; then
66+
echo "::error::packages/tugboat version must be bumped before merge (still $base_version)."
67+
exit 1
68+
fi
69+
70+
higher="$(printf '%s\n%s\n' "$base_version" "$head_version" | sort -V | tail -n 1)"
71+
if [[ "$higher" != "$head_version" ]]; then
72+
echo "::error::PR version ($head_version) must be greater than base ($base_version)."
73+
exit 1
74+
fi
75+
76+
echo "Version bump detected: $base_version -> $head_version"

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ verified in their own repositories.
2727

2828
## Current compatibility
2929

30-
- package version: `0.2.0`;
31-
- session JSON schema: `6`;
30+
- package version: `0.4.0`;
31+
- session JSON schema: `7`;
3232
- fingerprint schema: `6`;
3333
- minimum Dart SDK: `3.9.2`;
3434
- minimum Flutter SDK: `3.35.0`.

packages/tugboat/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ checkpoints around meaningful interactions, compact structural anchors, route
55
transitions, scrolling evidence, and optional viewport semantic maps. Capture
66
can be sent to the local exploration WebSocket, the HTTP collector, or both.
77

8-
The current package version is `0.2.0`. Session JSON uses schema version `7`
8+
The current package version is `0.4.0`. Session JSON uses schema version `7`
99
(readers still accept `6`), and structural fingerprints use fingerprint schema
1010
version `6`.
1111

packages/tugboat/example/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ resolution: workspace
3232
dependencies:
3333
flutter:
3434
sdk: flutter
35-
tugboat: ^0.2.0
35+
tugboat: ^0.4.0
3636

3737
# The following adds the Cupertino Icons font to your application.
3838
# Use with the CupertinoIcons class for iOS style icons.

packages/tugboat/lib/src/controller.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,6 +1329,31 @@ class TugboatReplayController extends ChangeNotifier {
13291329
});
13301330
}
13311331

1332+
void recordAppLifecycleState(AppLifecycleState state) {
1333+
_addEvent(
1334+
TugboatEvent(
1335+
id: _nextId('event'),
1336+
atMs: atMs,
1337+
type: _appLifecycleEventType(state),
1338+
data: {'state': state.name},
1339+
),
1340+
);
1341+
}
1342+
1343+
String _appLifecycleEventType(AppLifecycleState state) {
1344+
switch (state) {
1345+
case AppLifecycleState.paused:
1346+
case AppLifecycleState.hidden:
1347+
return 'app_backgrounded';
1348+
case AppLifecycleState.resumed:
1349+
return 'app_foregrounded';
1350+
case AppLifecycleState.inactive:
1351+
return 'app_inactive';
1352+
case AppLifecycleState.detached:
1353+
return 'app_detached';
1354+
}
1355+
}
1356+
13321357
_RouteTransition _parseRouteTransition(String type, Route<dynamic>? route) {
13331358
return _RouteTransition(
13341359
kind: _RouteNavigationKind.parse(type),
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// Keep this in sync with packages/tugboat/pubspec.yaml. The SDK version test
22
// reads pubspec.yaml directly so release bumps fail fast if this drifts.
3-
const tugboatSdkVersion = '0.2.0';
3+
const tugboatSdkVersion = '0.4.0';

packages/tugboat/lib/src/tugboat.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,9 @@ class _TugboatReplayRootState extends State<_TugboatReplayRoot>
299299

300300
@override
301301
void didChangeAppLifecycleState(AppLifecycleState state) {
302+
if (!TugboatReplay.disabled) {
303+
TugboatReplay.controller?.recordAppLifecycleState(state);
304+
}
302305
switch (state) {
303306
case AppLifecycleState.paused:
304307
case AppLifecycleState.hidden:

packages/tugboat/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: tugboat
22
description: >-
33
Screenshot-based session replay with compact interaction anchors for Tugboat.
4-
version: 0.3.0
4+
version: 0.4.0
55
repository: https://github.com/blendto/tugboat-flutter
66
issue_tracker: https://github.com/blendto/tugboat-flutter/issues
77
homepage: https://github.com/blendto/tugboat-flutter

packages/tugboat/test/tugboat_replay_test.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,42 @@ void main() {
9494
await tester.pump();
9595
});
9696

97+
testWidgets('app background and foreground transitions are explicit', (
98+
tester,
99+
) async {
100+
await tester.pumpWidget(
101+
MaterialApp(
102+
builder: (context, child) =>
103+
TugboatReplay.wrapApp(config: _testConfig, child: child!),
104+
home: const SizedBox.expand(),
105+
),
106+
);
107+
await tester.pump();
108+
109+
final session = TugboatReplay.controller!.session!;
110+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.paused);
111+
await tester.pump();
112+
tester.binding.handleAppLifecycleStateChanged(AppLifecycleState.resumed);
113+
await tester.pump();
114+
115+
final lifecycleEvents = session.events
116+
.where(
117+
(event) =>
118+
event.type == 'app_backgrounded' ||
119+
event.type == 'app_foregrounded',
120+
)
121+
.toList();
122+
expect(lifecycleEvents.length, greaterThanOrEqualTo(2));
123+
expect(
124+
lifecycleEvents.map((event) => event.type),
125+
containsAllInOrder(['app_backgrounded', 'app_foregrounded']),
126+
);
127+
expect(
128+
lifecycleEvents.map((event) => event.data['state']),
129+
containsAllInOrder(['paused', 'resumed']),
130+
);
131+
});
132+
97133
testWidgets('captures initial screenshot and tap interaction anchors', (
98134
tester,
99135
) async {

0 commit comments

Comments
 (0)