Skip to content

Reduce unnecessary API calls, startup work, and battery drain - #69

Open
khonager with Copilot wants to merge 2 commits into
unstablefrom
copilot/improve-api-requests
Open

Reduce unnecessary API calls, startup work, and battery drain#69
khonager with Copilot wants to merge 2 commits into
unstablefrom
copilot/improve-api-requests

Conversation

Copilot AI commented Mar 22, 2026

Copy link
Copy Markdown
Contributor

Several hot paths were making redundant network calls or duplicating initialization work on every invocation. Key areas: settings updates, location tracking during wake alarm, realtime message subscriptions, and notification plugin lifecycle.

Changes

  • Settings cacheupdateSettings previously did SELECT → merge → UPDATE on every call (2 round-trips per setting toggle). Now maintains _cachedSettings populated by loadAndSyncSettings; subsequent writes merge locally and go straight to UPDATE. Falls back to SELECT if the cache is cold.

  • updateThemeColor 3 → 1 API call – Was calling a column-level UPDATE then updateSettings (which itself was SELECT + UPDATE). Now merges theme_color_value into the settings cache and issues a single UPDATE covering both fields.

  • updateLocation ghost mode check – Was calling getCurrentProfile() (full network fetch) on every GPS event to read ghost_mode. During the wake alarm this fired every ~10 s (6 wasted fetches/min). Now reads from SharedPreferences, which is memory-cached after first access.

  • Message listener server-side filter – Added .eq('receiver_id', user.id) to _startMessageListener's Supabase stream. Previously streamed the last 5 messages globally and filtered client-side; now only events for the current user are delivered over the wire.

  • Single FlutterLocalNotificationsPlugin instanceRoutesTab was constructing a second plugin instance and calling .initialize() in initState, duplicating what NotificationManager.init() already does at startup. Added NotificationManager.plugin getter; RoutesTab now reuses it.

  • Wake alarm prefs read outside GPS loopalarm_stops_before and alarm_trigger_threshold were fetched from SharedPreferences on every position event inside the stream listener. Both are now read once before the stream starts and captured as closure variables.

Original prompt

i want you to look at the codebase. i'm going to release a new public version soon and i was wondering if there is anything that can be improved or looks like it is missing something. most important things are probably unnecessary api requests, startup time, background tasks/battery consumtion.


📍 Connect Copilot coding agent with Jira, Azure Boards or Linear to delegate work to Copilot in one click without leaving your project management tool.

- Cache settings in memory to eliminate SELECT roundtrip on every settings
  update (falls back to DB fetch when cache is unpopulated)
- Collapse updateThemeColor from 3 to 1 API call by combining the dedicated
  column update and settings JSON update in a single request
- Replace getCurrentProfile() in updateLocation with a SharedPreferences
  ghost_mode read (memory-cached) to avoid a network call on each GPS event
- Add server-side receiver_id filter to _startMessageListener so only
  messages addressed to the current user are delivered over the wire
- Expose NotificationManager.plugin and reuse it in RoutesTab instead of
  creating a second FlutterLocalNotificationsPlugin instance and calling
  initialize() a second time at startup
- Cache wake alarm settings (alarm_stops_before, alarm_trigger_threshold)
  before starting the GPS stream instead of reading SharedPreferences on
  every GPS position event

Co-authored-by: khonager <71403572+khonager@users.noreply.github.com>
Agent-Logs-Url: https://github.com/khonager/Trans/sessions/ba1ccabe-3880-414d-ae97-53df8d35cd91
Copilot AI changed the title [WIP] Analyze codebase for potential improvements before public release Reduce unnecessary API calls, startup work, and battery drain Mar 22, 2026
Copilot AI requested a review from khonager March 22, 2026 13:34
@khonager
khonager marked this pull request as ready for review March 22, 2026 13:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR reduces redundant network calls and repeated initialization work in hot paths (settings updates, location tracking during the wake alarm, realtime message subscriptions, and local notification plugin lifecycle) to improve startup cost and battery/network usage.

Changes:

  • Added an in-memory settings JSON cache to avoid an extra SELECT on each updateSettings call, and consolidated updateThemeColor into a single UPDATE request.
  • Reduced wake-alarm background overhead by avoiding per-position preference reads and by checking ghost mode from SharedPreferences instead of fetching the profile every time.
  • Narrowed the messages realtime stream to only the current receiver and removed duplicate notification plugin initialization by reusing a shared instance.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
lib/services/supabase_service.dart Adds settings cache + reduces settings/theme-color roundtrips; reduces GPS-update network/profile fetch work; adds receiver filter to message stream
lib/services/notification_manager.dart Exposes a shared, already-initialized notifications plugin instance
lib/screens/tabs/routes_tab.dart Reuses the shared notifications plugin and moves wake-alarm preference reads outside the GPS loop
Comments suppressed due to low confidence (1)

lib/services/supabase_service.dart:279

  • The new in-memory _cachedSettings fast-path means updateSettings can now write based on a potentially stale snapshot (e.g., settings changed from another device/session while the app is running). That can cause lost updates because the whole settings JSON is rewritten each time. If multi-device sync matters, consider updating settings server-side with a JSON merge/patch operation (so only the provided keys are overwritten) or periodically reloading/invalidating the cache before writes.
      Map<String, dynamic> base;
      if (_cachedSettings != null) {
        // Fast path: merge into the in-memory cache to avoid a SELECT roundtrip.
        base = Map<String, dynamic>.from(_cachedSettings!);
      } else {
        // Cache not yet populated (e.g. settings changed before loadAndSyncSettings
        // completed). Fall back to fetching the current value from the database.
        final res = await client
            .from('profiles')
            .select('settings')
            .eq('id', user.id)
            .single();
        base = Map<String, dynamic>.from(res['settings'] ?? {});
      }

      final updatedSettings = base..addAll(newSettings);
      _cachedSettings = updatedSettings;

      await client
          .from('profiles')
          .update({'settings': updatedSettings}).eq('id', user.id);

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +234 to +250
try {
final res = await client
.from('profiles')
.select('settings')
.eq('id', user.id)
.single();
base = Map<String, dynamic>.from(res['settings'] ?? {});
} catch (_) {
base = {};
}
}
final updatedSettings = base..addAll({'theme_color_value': colorValue});
_cachedSettings = updatedSettings;
await client.from('profiles').update({
'theme_color': colorValue,
'settings': updatedSettings,
}).eq('id', user.id);

Copilot AI Mar 22, 2026

Copy link

Choose a reason for hiding this comment

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

In updateThemeColor, if the SELECT settings fails you fall back to base = {} but still send an UPDATE that sets the settings column to only {theme_color_value: ...}. This would overwrite/wipe any existing settings JSON on transient network/RLS errors. Consider only updating the theme_color column when the settings cache is cold and the SELECT fails (or bail out), and only include settings in the UPDATE when you have a reliable base (cache hit or successful fetch).

Copilot uses AI. Check for mistakes.
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.

3 participants