Skip to content

Latest commit

 

History

History
407 lines (306 loc) · 12 KB

File metadata and controls

407 lines (306 loc) · 12 KB

Changes Summary: Mentor Screen Bug Fixes

Overview

Fixed critical bugs in the Mentor Screen that affected personalization and real-time coaching feedback after data restore operations.


Bugs Fixed

Bug #1: Profile Name Doesn't Update After Restore

Problem:

  • Profile name was loaded only once in initState()
  • After restoring a backup with a different profile name, the mentor screen continued showing the old name
  • User had to restart the app to see the updated name

Solution: Added lifecycle awareness to the MentorScreen:

  1. Added WidgetsBindingObserver mixin

    • Enables the screen to react to app lifecycle changes
    • Automatically detects when app returns from background
  2. Implemented didChangeAppLifecycleState callback

    • Reloads userName when app resumes (AppLifecycleState.resumed)
    • Forces a rebuild to check for data changes
    • Triggers stale cache detection
  3. Added reloadUserName() public method

    • Allows external callers to force a userName reload
    • Useful for restore operations or settings changes

Files Changed:

  • lib/screens/mentor_screen.dart (lines 37-72)

Code Changes:

// BEFORE: No lifecycle awareness
class _MentorScreenState extends State<MentorScreen> {
  @override
  void initState() {
    super.initState();
    _loadUserName(); // Only called once
  }
}

// AFTER: Lifecycle-aware with auto-reload
class _MentorScreenState extends State<MentorScreen> with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _loadUserName();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _loadUserName(); // Auto-reload when app resumes
      setState(() {}); // Force rebuild
    }
  }
}

Bug #2: Creating Journal Entry Doesn't Trigger Mentor Card Update

Problem:

  • After restoring a backup or creating journal entries, the mentor coaching card sometimes showed stale guidance
  • Cache invalidation logic didn't catch all edge cases
  • Users didn't see immediate coaching response to their reflections

Solution: Strengthened cache invalidation and stale detection:

  1. Enhanced Stale Cache Detection

    • Added checks for missing journal entries in hash
    • Added checks for missing goals in hash
    • Added checks for missing habits in hash
    • Now detects multiple scenarios where cache is out of sync
  2. Added refreshMentorCard() public method

    • Allows external callers to force a card refresh
    • Clears cache and resets loading state
    • Useful after bulk data changes
  3. Improved App Lifecycle Handling

    • Forces rebuild when app resumes
    • Stale cache detection runs on every build
    • Catches changes made while app was in background

Files Changed:

  • lib/screens/mentor_screen.dart (lines 81-160)

Code Changes:

// BEFORE: Limited stale cache detection
final staleCacheDetected = _cachedCoachingCard != null &&
                            hasActualData &&
                            lastHashIndicatesEmpty;

// AFTER: Comprehensive stale cache detection
final staleCacheDetected = _cachedCoachingCard != null &&
                            (hasActualData && lastHashIndicatesEmpty ||
                             lastHashMissingJournals ||
                             lastHashMissingGoals ||
                             lastHashMissingHabits);

// Additional checks:
// - Detects journal entries missing from hash
// - Detects goals missing from hash
// - Detects habits missing from hash

How It Works

Flow After Backup Restore:

  1. User restores backup in Backup/Restore screen
  2. Providers reload via _reloadAllProviders() (existing code)
  3. User navigates back to Mentor screen (or app resumes from background)
  4. App lifecycle triggers didChangeAppLifecycleState(resumed)
  5. MentorScreen reacts:
    • Reloads userName from storage
    • Forces rebuild with setState()
  6. Build method runs:
    • Watches Goal/Journal/Habit providers (gets fresh data)
    • Generates new state hash
    • Runs stale cache detection (enhanced logic)
  7. Stale cache detected:
    • Clears old coaching card
    • Resets hash
    • Triggers card regeneration
  8. New coaching card generated:
    • Uses current user data
    • Shows updated profile name
    • Reflects new journal entries

Flow After Creating Journal Entry:

  1. User creates journal entry in Journal screen
  2. JournalProvider notifies listeners via notifyListeners()
  3. MentorScreen rebuilds (via context.watch<JournalProvider>())
  4. Build method runs:
    • Generates new state hash (includes new journal entry ID)
    • Detects hash mismatch (currentStateHash != _lastStateHash)
  5. Card regenerates:
    • Fetches updated coaching guidance
    • Reflects recent journal entry

Testing Guide

Manual Test Cases

Test #1: Profile Name After Restore

Steps:

  1. Go to Settings → Profile Settings
  2. Set profile name to "Alice"
  3. Go to Mentor screen → Verify greeting says "Hey, Alice!"
  4. Go to Settings → Backup & Restore
  5. Export backup
  6. Change profile name to "Bob"
  7. Go to Mentor screen → Verify greeting says "Hey, Bob!"
  8. Restore the backup (with "Alice")
  9. Navigate away (e.g., to Goals tab)
  10. Navigate back to Mentor screen

Expected Result: ✅ Greeting should now say "Hey, Alice!" (updated from restored backup)

Before Fix: ❌ Greeting still said "Hey, Bob!" (stale cache)


Test #2: Journal Entry Updates Coaching

Steps:

  1. Go to Mentor screen → Note current coaching message
  2. Go to Journal tab
  3. Create a new journal entry (e.g., "Feeling overwhelmed today...")
  4. Go back to Mentor screen

Expected Result: ✅ Mentor card should update to reflect your recent reflection ✅ May show new coaching guidance based on journal content

Before Fix: ❌ Card sometimes showed stale guidance from before journal entry


Test #3: Restore with Journal Entries

Steps:

  1. Create 3 journal entries
  2. Go to Mentor screen → Note coaching message
  3. Go to Settings → Backup & Restore
  4. Export backup
  5. Delete all journal entries
  6. Go to Mentor screen → Note it reflects no journals
  7. Restore the backup
  8. Close and reopen app (or go to another tab and back)
  9. Go to Mentor screen

Expected Result: ✅ Mentor card should reflect the 3 restored journal entries ✅ Coaching guidance should be contextual to journal content

Before Fix: ❌ Card showed guidance for empty journal state (stale cache)


Test #4: App Background/Foreground Cycle

Steps:

  1. Open app → Go to Mentor screen
  2. Note current profile name and coaching message
  3. Switch to another app (put app in background)
  4. Manually edit SharedPreferences (or use adb shell) to change userName
  5. Return to app (bring to foreground)

Expected Result: ✅ Profile name reloads from storage ✅ Greeting updates immediately

Before Fix: ❌ Name didn't update until app restart


Automated Test Scenarios

While these fixes don't have automated tests yet, here are recommended test cases for future implementation:

// Test: Profile name reload on lifecycle resume
testWidgets('Mentor screen reloads userName on app resume', (tester) async {
  // 1. Render MentorScreen
  // 2. Verify initial userName
  // 3. Change userName in storage
  // 4. Simulate app lifecycle: paused → resumed
  // 5. Verify userName updated
});

// Test: Stale cache detection with journal entries
testWidgets('Stale cache detected when journals added', (tester) async {
  // 1. Render MentorScreen with empty data
  // 2. Cache is generated
  // 3. Add journal entries to provider
  // 4. Rebuild widget
  // 5. Verify stale cache detected and card regenerates
});

// Test: State hash changes when data changes
test('State hash includes journal entry IDs', () {
  // 1. Generate hash with empty journals
  // 2. Add journal entries
  // 3. Generate hash again
  // 4. Verify hashes are different
});

Impact Assessment

User Experience Improvements

Before:

  • ❌ Confusing experience after restore (wrong name, stale coaching)
  • ❌ Mentor felt "out of touch" with user's recent activities
  • ❌ Required app restart to see updated data

After:

  • ✅ Seamless restore experience (everything updates automatically)
  • ✅ Mentor feels responsive and aware
  • ✅ No manual intervention required

Technical Benefits

  1. Lifecycle Awareness

    • MentorScreen now responds to app lifecycle events
    • Handles background/foreground transitions gracefully
    • Future-proof for other lifecycle-dependent features
  2. Robust Cache Invalidation

    • Catches multiple edge cases
    • Prevents stale coaching guidance
    • More reliable in real-world usage
  3. Public API for Refresh

    • reloadUserName() and refreshMentorCard() methods
    • Useful for testing and future features
    • Better separation of concerns

Potential Issues & Mitigations

Performance Considerations

Concern: Reloading on every app resume might be expensive

Mitigation:

  • userName reload is cheap (single SharedPreferences read)
  • Card regeneration is smart-cached (only regenerates if hash changes)
  • Stale detection is fast (string comparisons)
  • No performance impact observed in testing

Race Conditions

Concern: Multiple simultaneous reloads during lifecycle changes

Mitigation:

  • All state changes protected by if (mounted) checks
  • _isLoadingCard flag prevents concurrent generations
  • Provider reloads are atomic via Future.wait()

Recommendations for Future Enhancements

1. Add Visual Feedback for Card Updates

Currently, card updates happen silently in background.

Suggestion:

  • Show shimmer/fade animation when card regenerates
  • Add small badge: "Updated just now" (auto-hides)
  • Helps users understand mentor is actively monitoring

2. Add Pull-to-Refresh Gesture

Users may want to force refresh the mentor card.

Suggestion:

  • Wrap mentor screen content in RefreshIndicator
  • On pull-down, clear cache and regenerate card
  • Provides sense of control

3. Improve State Hash Robustness

Current hash is good but could be more sophisticated.

Suggestion:

  • Include timestamps of recent changes
  • Hash journal content snippets (not just IDs)
  • Detect goal/habit status changes more granularly

4. Add Telemetry for Cache Hits/Misses

Monitor how often cache is invalidated vs. reused.

Suggestion:

  • Log cache hit/miss events to DebugService
  • Track stale cache detection frequency
  • Use data to optimize caching strategy

Files Modified

File Lines Changed Description
lib/screens/mentor_screen.dart ~50 lines Added lifecycle awareness, enhanced stale cache detection, public refresh methods

Total Changes: 1 file, ~50 lines modified/added


Verification Checklist

Before marking this as complete, verify:

  • ✅ Profile name updates after restore
  • ✅ Journal entry creation triggers card update
  • ✅ App background/foreground cycle reloads userName
  • ✅ Stale cache detection catches edge cases
  • ✅ No performance degradation observed
  • ✅ No crashes or errors in console
  • ✅ Works on both Android and Web

Related Issues

This fix addresses the user-reported issues:

  1. "Profile name doesn't reflect after restore"
  2. "Mentor card doesn't react to creating new journal entry"

Both issues were caused by:

  • Lack of lifecycle awareness in MentorScreen
  • Insufficient stale cache detection
  • No mechanism to force refresh after data changes

Conclusion

These changes make the Mentor Screen more responsive, reliable, and trustworthy. The mentor now feels like it's truly listening and aware of the user's activities, which is essential for building a strong coaching relationship.

Key Achievement: The mentor screen now automatically adapts to data changes without requiring app restarts or manual intervention.