feat(android): add runtime starred plans management API
- Add updateStarredPlans() method to update plan IDs from TimeSafari app - Stores plan IDs in SharedPreferences for persistence - Integrated with TimeSafariIntegrationManager for prefetch operations - Includes comprehensive logging for debugging - Add getStarredPlans() method to retrieve current stored plan IDs - Allows TimeSafari app to verify synchronization - Returns count and last update timestamp - Update TimeSafariIntegrationManager to load starred plan IDs - Reads from SharedPreferences when building TimeSafariUserConfig - Used automatically by EnhancedDailyNotificationFetcher for API calls - Enables dynamic updates without requiring app restart - Add TypeScript definitions for new methods - Includes JSDoc documentation for integration guidance - Matches Android implementation return types - Create integration example for TimeSafari app - Shows how to sync plan IDs from account settings - Demonstrates star/unstar action handling - Includes verification and error handling patterns This allows the TimeSafari app to dynamically update starred project IDs when users star or unstar projects, without requiring plugin configuration changes or app restarts. The stored IDs are automatically used by the prefetch system to query for project updates.
This commit is contained in:
@@ -1786,6 +1786,126 @@ public class DailyNotificationPlugin extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update starred plan IDs from host application
|
||||
*
|
||||
* This allows the TimeSafari app to dynamically update the list of starred
|
||||
* project IDs when users star or unstar projects. The IDs are stored persistently
|
||||
* and used for prefetch operations that query for starred project updates.
|
||||
*
|
||||
* @param call Contains:
|
||||
* - planIds: string[] - Array of starred plan handle IDs
|
||||
*/
|
||||
@PluginMethod
|
||||
public void updateStarredPlans(PluginCall call) {
|
||||
try {
|
||||
JSObject data = call.getData();
|
||||
if (data == null) {
|
||||
call.reject("No data provided");
|
||||
return;
|
||||
}
|
||||
|
||||
Object planIdsObj = data.get("planIds");
|
||||
if (planIdsObj == null) {
|
||||
call.reject("planIds is required");
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert to List<String>
|
||||
List<String> planIds;
|
||||
if (planIdsObj instanceof List) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> objList = (List<Object>) planIdsObj;
|
||||
planIds = new java.util.ArrayList<>();
|
||||
for (Object obj : objList) {
|
||||
if (obj != null) {
|
||||
planIds.add(obj.toString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call.reject("planIds must be an array");
|
||||
return;
|
||||
}
|
||||
|
||||
Log.i(TAG, "DN|UPDATE_STARRED_PLANS count=" + planIds.size());
|
||||
|
||||
// Store in SharedPreferences for persistence
|
||||
SharedPreferences preferences = getContext()
|
||||
.getSharedPreferences("daily_notification_timesafari", Context.MODE_PRIVATE);
|
||||
|
||||
// Store as JSON string for easy retrieval
|
||||
org.json.JSONArray jsonArray = new org.json.JSONArray();
|
||||
for (String planId : planIds) {
|
||||
jsonArray.put(planId);
|
||||
}
|
||||
|
||||
preferences.edit()
|
||||
.putString("starredPlanIds", jsonArray.toString())
|
||||
.putLong("starredPlansUpdatedAt", System.currentTimeMillis())
|
||||
.apply();
|
||||
|
||||
Log.d(TAG, "DN|STARRED_PLANS_STORED count=" + planIds.size() +
|
||||
" stored_at=" + System.currentTimeMillis());
|
||||
|
||||
// Update TimeSafariIntegrationManager if it needs the IDs immediately
|
||||
if (timeSafariIntegration != null) {
|
||||
// The TimeSafariIntegrationManager will read from SharedPreferences
|
||||
// when it needs the starred plan IDs, so no direct update needed
|
||||
Log.d(TAG, "DN|STARRED_PLANS_UPDATED TimeSafariIntegrationManager will use stored IDs");
|
||||
}
|
||||
|
||||
JSObject result = new JSObject();
|
||||
result.put("success", true);
|
||||
result.put("planIdsCount", planIds.size());
|
||||
result.put("updatedAt", System.currentTimeMillis());
|
||||
|
||||
call.resolve(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "DN|UPDATE_STARRED_PLANS_ERR Error updating starred plans", e);
|
||||
call.reject("Error updating starred plans: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current starred plan IDs
|
||||
*
|
||||
* Returns the currently stored starred plan IDs from SharedPreferences.
|
||||
* This is useful for the host app to verify what IDs are stored.
|
||||
*/
|
||||
@PluginMethod
|
||||
public void getStarredPlans(PluginCall call) {
|
||||
try {
|
||||
SharedPreferences preferences = getContext()
|
||||
.getSharedPreferences("daily_notification_timesafari", Context.MODE_PRIVATE);
|
||||
|
||||
String starredPlansJson = preferences.getString("starredPlanIds", "[]");
|
||||
long updatedAt = preferences.getLong("starredPlansUpdatedAt", 0);
|
||||
|
||||
org.json.JSONArray jsonArray = new org.json.JSONArray(starredPlansJson);
|
||||
List<String> planIds = new java.util.ArrayList<>();
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
planIds.add(jsonArray.getString(i));
|
||||
}
|
||||
|
||||
JSObject result = new JSObject();
|
||||
org.json.JSONArray planIdsArray = new org.json.JSONArray();
|
||||
for (String planId : planIds) {
|
||||
planIdsArray.put(planId);
|
||||
}
|
||||
result.put("planIds", planIdsArray);
|
||||
result.put("count", planIds.size());
|
||||
result.put("updatedAt", updatedAt);
|
||||
|
||||
Log.d(TAG, "DN|GET_STARRED_PLANS count=" + planIds.size());
|
||||
call.resolve(result);
|
||||
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "DN|GET_STARRED_PLANS_ERR Error getting starred plans", e);
|
||||
call.reject("Error getting starred plans: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test JWT generation for debugging
|
||||
*/
|
||||
|
||||
@@ -27,18 +27,23 @@
|
||||
package com.timesafari.dailynotification;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* TimeSafari Integration Manager
|
||||
*
|
||||
@@ -272,6 +277,11 @@ public final class TimeSafariIntegrationManager {
|
||||
userConfig.fetchOffersToProjects = true;
|
||||
userConfig.fetchProjectUpdates = true;
|
||||
|
||||
// Load starred plan IDs from SharedPreferences
|
||||
userConfig.starredPlanIds = loadStarredPlanIdsFromSharedPreferences();
|
||||
logger.d("TS: Loaded starredPlanIds count=" +
|
||||
(userConfig.starredPlanIds != null ? userConfig.starredPlanIds.size() : 0));
|
||||
|
||||
// 3) Execute fetch (async, but we wait in executor)
|
||||
CompletableFuture<EnhancedDailyNotificationFetcher.TimeSafariNotificationBundle> future =
|
||||
fetcher.fetchAllTimeSafariData(userConfig);
|
||||
@@ -584,5 +594,47 @@ public final class TimeSafariIntegrationManager {
|
||||
// If you replace the Executor with something closeable, do it here
|
||||
// For now, single-threaded executor will be GC'd when manager is GC'd
|
||||
}
|
||||
|
||||
/* ============================================================
|
||||
* Helper Methods
|
||||
* ============================================================ */
|
||||
|
||||
/**
|
||||
* Load starred plan IDs from SharedPreferences
|
||||
*
|
||||
* Reads the persisted starred plan IDs that were stored via
|
||||
* DailyNotificationPlugin.updateStarredPlans()
|
||||
*
|
||||
* @return List of starred plan IDs, or empty list if none stored
|
||||
*/
|
||||
@NonNull
|
||||
private List<String> loadStarredPlanIdsFromSharedPreferences() {
|
||||
try {
|
||||
SharedPreferences preferences = appContext
|
||||
.getSharedPreferences("daily_notification_timesafari", Context.MODE_PRIVATE);
|
||||
|
||||
String starredPlansJson = preferences.getString("starredPlanIds", "[]");
|
||||
|
||||
if (starredPlansJson == null || starredPlansJson.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
JSONArray jsonArray = new JSONArray(starredPlansJson);
|
||||
List<String> planIds = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < jsonArray.length(); i++) {
|
||||
planIds.add(jsonArray.getString(i));
|
||||
}
|
||||
|
||||
return planIds;
|
||||
|
||||
} catch (JSONException e) {
|
||||
logger.e("TS: Error parsing starredPlanIds from SharedPreferences", e);
|
||||
return new ArrayList<>();
|
||||
} catch (Exception e) {
|
||||
logger.e("TS: Unexpected error loading starredPlanIds", e);
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user