/** * FetchContext.java * * Context information provided to content fetchers about why a fetch was triggered. * * This class is part of the Integration Point Refactor (PR1) SPI implementation. * It provides fetchers with metadata about the fetch request, including trigger * type, scheduling information, and optional metadata. * * @author Matthew Raymer * @version 1.0.0 */ package com.timesafari.dailynotification; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import java.util.Collections; import java.util.HashMap; import java.util.Map; /** * Context provided to content fetchers about why fetch was triggered * * This follows the TypeScript interface from src/types/content-fetcher.ts and * ensures type safety between JS and native fetcher implementations. */ public class FetchContext { /** * Reason why the fetch was triggered * * Valid values: "background_work", "prefetch", "manual", "scheduled" */ @NonNull public final String trigger; /** * When notification is scheduled for (optional, epoch milliseconds) * * Only present when trigger is "prefetch" or "scheduled" */ @Nullable public final Long scheduledTime; /** * When the fetch was triggered (required, epoch milliseconds) */ public final long fetchTime; /** * Additional context metadata (optional) * * Plugin may populate with app state, network info, etc. * Fetcher can use for logging, debugging, or conditional logic. */ @NonNull public final Map metadata; /** * Constructor with all fields * * @param trigger Trigger type (required) * @param scheduledTime Scheduled time (optional) * @param fetchTime When fetch triggered (required) * @param metadata Additional metadata (optional, can be null) */ public FetchContext( @NonNull String trigger, @Nullable Long scheduledTime, long fetchTime, @Nullable Map metadata) { if (trigger == null || trigger.isEmpty()) { throw new IllegalArgumentException("trigger is required"); } this.trigger = trigger; this.scheduledTime = scheduledTime; this.fetchTime = fetchTime; this.metadata = metadata != null ? Collections.unmodifiableMap(new HashMap<>(metadata)) : Collections.emptyMap(); } /** * Constructor with minimal fields (no metadata) * * @param trigger Trigger type * @param scheduledTime Scheduled time (can be null) * @param fetchTime When fetch triggered */ public FetchContext( @NonNull String trigger, @Nullable Long scheduledTime, long fetchTime) { this(trigger, scheduledTime, fetchTime, null); } /** * Get metadata value by key * * @param key Metadata key * @return Value or null if not present */ @Nullable public Object getMetadata(@NonNull String key) { return metadata.get(key); } /** * Check if metadata contains key * * @param key Metadata key * @return True if key exists */ public boolean hasMetadata(@NonNull String key) { return metadata.containsKey(key); } @Override public String toString() { return "FetchContext{" + "trigger='" + trigger + '\'' + ", scheduledTime=" + scheduledTime + ", fetchTime=" + fetchTime + ", metadataSize=" + metadata.size() + '}'; } }