Skip to content

fix(BAL-211): fix game session duration not logged when app closed mid-game#212

Merged
sebastianricaldoni merged 4 commits into
mainfrom
bug/BAL-211-SR-fix-game-session-duration-logging
Jun 10, 2026
Merged

fix(BAL-211): fix game session duration not logged when app closed mid-game#212
sebastianricaldoni merged 4 commits into
mainfrom
bug/BAL-211-SR-fix-game-session-duration-logging

Conversation

@sebastianricaldoni

Copy link
Copy Markdown
Collaborator

Summary

  • Root cause: onDisappear never fires when user closes app mid-game — iOS keeps views mounted on background. Session duration stayed 0 seconds.
  • Fix: Refactor activity logging from fragile string-matching ("Opened X" / "Closed X") to a clean push(viewName:) + finalizePending() stack model. App background triggers finalizePending() via a synchronous UIApplication.willEnterForegroundNotification observer — guaranteed to fire before any SwiftUI view events.

Changes

  • ActivityStorageManager — New push(viewName:) / finalizePending() API replaces addAction / endLog / finalizeOpenActions. ActivityLogEntry now owns its own reset logic via NotificationCenter observer. actions renamed to entries internally (JSON key preserved as "actions" for backwards compatibility with existing user data).
  • ActivityLogBaseView — Uses new push/finalize API. onDisappear guards against double-finalize on forward navigation (child onAppear fires before parent onDisappear in NavigationStack). Adds didBecomeActiveNotification handler as fallback for when onAppear doesn't fire on resume.
  • HomeActivityLogBaseView("Home") moved inside NavigationStack root so SwiftUI correctly fires onAppear/onDisappear on forward/back navigation.
  • ProfileView — Share buttons do fresh file load on tap (single source of truth). ShareLink replaced with Button + UIActivityViewController to avoid eager CSV computation on every render.
  • SpotifyViewController — Updated to new API.
  • BalanceExtensions — Added Encodable.toJSON() debug utility (DEBUG only).

Test plan

  • Open a game, play for 30+ seconds, kill app from home screen — verify session duration > 0 in CSV
  • Open a game, play, press back — verify duration logged correctly
  • Navigate Home → Feature → Sub-feature → back → back — verify all durations logged
  • Background and resume app multiple times — verify no duplicate entries
  • Share data via email and share sheet — verify CSV contains current session

Closes #211

🤖 Generated with Claude Code

- Add finalizeOpenActions() to close pending "Opened X" actions when
  app backgrounds, fixing zero-duration bug when app is killed mid-game
- Move reset() logic to UIApplication.willEnterForegroundNotification
  observer on ActivityLogEntry (synchronous, fires before SwiftUI views)
  to avoid race condition with async saveLog on background
- Add didBecomeActiveNotification handler in ActivityLogBaseView with
  isVisible guard to re-log current view on resume when onAppear does
  not fire reliably
- Add Home view logging via ActivityLogBaseView wrapper
- Add Encodable.toJSON() debug utility in BalanceExtensions
- Fix WKCompanionAppBundleIdentifier for local device signing
…model

Replace fragile "Opened X" / "Closed X" string-matching with a clean
push(viewName:) + finalizePending() stack model:

- push() finalizes previous pending entry then opens a new one
- finalizePending() closes current entry with correct duration
- onDisappear only finalizes if pendingEntry matches view (guards
  against forward-nav double-finalize since onAppear fires first)
- ActivityLogEntry observes willEnterForegroundNotification directly
  (synchronous, before SwiftUI views) to guarantee reset fires before
  any onAppear on resume
- ActivityLogBaseView uses didBecomeActiveNotification + isVisible guard
  to re-push current view when onAppear does not fire on resume
- Home ActivityLogBaseView moved inside NavigationStack root so
  onAppear/onDisappear fire correctly on forward/back navigation
- Rename actions → entries (CodingKeys maps to "actions" for backwards
  compatibility with existing user data)
- addActionButton renamed to addButtonEvent for clarity
- Coins eligibility extracted to Set<String> replacing long if-chain
- ProfileView share buttons do fresh file load on tap (single source of
  truth); ShareLink replaced with Button + UIActivityViewController
- SpotifyViewController updated to new push/finalizePending API
@codecov

codecov Bot commented Jun 9, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 12.50000% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 5.23%. Comparing base (1d94b54) to head (405b51d).

Files with missing lines Patch % Lines
...lance/ActivityLogging/ActivityStorageManager.swift 30.00% 7 Missing ⚠️
Balance/Profile/ProfileView.swift 0.00% 7 Missing ⚠️
Balance/ActivityLogging/ActivityLogBaseView.swift 0.00% 4 Missing ⚠️
Balance/Home/Home.swift 0.00% 2 Missing ⚠️
Balance/Utils/BalanceExtensions.swift 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff            @@
##            main    #212      +/-   ##
========================================
+ Coverage   5.06%   5.23%   +0.18%     
========================================
  Files        130     130              
  Lines       2158    2142      -16     
========================================
+ Hits         109     112       +3     
+ Misses      2049    2030      -19     
Files with missing lines Coverage Δ
...lance/ActivityLogging/ActivityLogButtonStyle.swift 0.00% <ø> (ø)
Balance/Balance.swift 76.20% <ø> (+3.47%) ⬆️
...traction/Music/iOS_SDK/SpotifyViewController.swift 24.33% <ø> (ø)
Balance/Utils/BalanceExtensions.swift 4.35% <0.00%> (-0.19%) ⬇️
Balance/Home/Home.swift 0.00% <0.00%> (ø)
Balance/ActivityLogging/ActivityLogBaseView.swift 0.00% <0.00%> (ø)
...lance/ActivityLogging/ActivityStorageManager.swift 34.79% <30.00%> (+23.16%) ⬆️
Balance/Profile/ProfileView.swift 0.00% <0.00%> (ø)

Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 1d94b54...405b51d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sebastianricaldoni sebastianricaldoni self-assigned this Jun 9, 2026

@gperissetcelteeka gperissetcelteeka left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@sebastianricaldoni sebastianricaldoni merged commit 689a7a2 into main Jun 10, 2026
5 checks passed
@sebastianricaldoni sebastianricaldoni deleted the bug/BAL-211-SR-fix-game-session-duration-logging branch June 10, 2026 12:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Games not logging session duration when app closed mid-game

2 participants