You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							740 lines
						
					
					
						
							23 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							740 lines
						
					
					
						
							23 KiB
						
					
					
				
								/**
							 | 
						|
								 * TimeSafari PWA - CapacitorPlatformService Clean Integration Example
							 | 
						|
								 * 
							 | 
						|
								 * This example shows the ACTUAL CHANGES needed to the existing TimeSafari PWA
							 | 
						|
								 * CapacitorPlatformService to add DailyNotification plugin functionality.
							 | 
						|
								 * 
							 | 
						|
								 * The plugin code ONLY touches Capacitor classes - no isCapacitor flags needed.
							 | 
						|
								 * 
							 | 
						|
								 * @author Matthew Raymer
							 | 
						|
								 * @version 1.0.0
							 | 
						|
								 */
							 | 
						|
								
							 | 
						|
								// =================================================
							 | 
						|
								// EXISTING TIMESAFARI PWA CODE (unchanged)
							 | 
						|
								// =================================================
							 | 
						|
								
							 | 
						|
								import { CameraDirection } from "@capacitor/camera";
							 | 
						|
								import { Capacitor } from "@capacitor/core";
							 | 
						|
								import {
							 | 
						|
								  SQLiteConnection,
							 | 
						|
								  SQLiteDBConnection,
							 | 
						|
								  CapacitorSQLite,
							 | 
						|
								} from "@capacitor-community/sqlite";
							 | 
						|
								
							 | 
						|
								import { QueryExecResult } from "@/interfaces/database";
							 | 
						|
								import {
							 | 
						|
								  PlatformService,
							 | 
						|
								  PlatformCapabilities,
							 | 
						|
								} from "../PlatformService";
							 | 
						|
								import { logger } from "../../utils/logger";
							 | 
						|
								
							 | 
						|
								// =================================================
							 | 
						|
								// NEW IMPORTS FOR DAILYNOTIFICATION PLUGIN
							 | 
						|
								// =================================================
							 | 
						|
								
							 | 
						|
								import { DailyNotification } from '@timesafari/daily-notification-plugin';
							 | 
						|
								import { TimeSafariIntegrationService } from '@timesafari/daily-notification-plugin';
							 | 
						|
								
							 | 
						|
								// =================================================
							 | 
						|
								// EXISTING INTERFACES (unchanged)
							 | 
						|
								// =================================================
							 | 
						|
								
							 | 
						|
								interface QueuedOperation {
							 | 
						|
								  type: "run" | "query" | "rawQuery";
							 | 
						|
								  sql: string;
							 | 
						|
								  params: unknown[];
							 | 
						|
								  resolve: (value: unknown) => void;
							 | 
						|
								  reject: (reason: unknown) => void;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// =================================================
							 | 
						|
								// NEW INTERFACES FOR DAILYNOTIFICATION PLUGIN
							 | 
						|
								// =================================================
							 | 
						|
								
							 | 
						|
								interface PlanSummaryAndPreviousClaim {
							 | 
						|
								  id: string;
							 | 
						|
								  title: string;
							 | 
						|
								  description: string;
							 | 
						|
								  lastUpdated: string;
							 | 
						|
								  previousClaim?: unknown;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								interface StarredProjectsResponse {
							 | 
						|
								  data: Array<PlanSummaryAndPreviousClaim>;
							 | 
						|
								  hitLimit: boolean;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								interface TimeSafariSettings {
							 | 
						|
								  accountDid?: string;
							 | 
						|
								  activeDid?: string;
							 | 
						|
								  apiServer?: string;
							 | 
						|
								  starredPlanHandleIds?: string[];
							 | 
						|
								  lastAckedStarredPlanChangesJwtId?: string;
							 | 
						|
								  [key: string]: unknown;
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								/**
							 | 
						|
								 * EXTENDED CapacitorPlatformService with DailyNotification Integration
							 | 
						|
								 * 
							 | 
						|
								 * This shows the ACTUAL CHANGES needed to the existing TimeSafari PWA
							 | 
						|
								 * CapacitorPlatformService class. The plugin code ONLY touches this class.
							 | 
						|
								 */
							 | 
						|
								export class CapacitorPlatformService implements PlatformService {
							 | 
						|
								  // =================================================
							 | 
						|
								  // EXISTING PROPERTIES (unchanged)
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /** Current camera direction */
							 | 
						|
								  private currentDirection: CameraDirection = CameraDirection.Rear;
							 | 
						|
								
							 | 
						|
								  private sqlite: SQLiteConnection;
							 | 
						|
								  private db: SQLiteDBConnection | null = null;
							 | 
						|
								  private dbName = "timesafari.sqlite";
							 | 
						|
								  private initialized = false;
							 | 
						|
								  private initializationPromise: Promise<void> | null = null;
							 | 
						|
								  private operationQueue: Array<QueuedOperation> = [];
							 | 
						|
								  private isProcessingQueue = false;
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW PROPERTIES FOR DAILYNOTIFICATION PLUGIN
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  private dailyNotificationService: DailyNotification | null = null;
							 | 
						|
								  private integrationService: TimeSafariIntegrationService | null = null;
							 | 
						|
								  private dailyNotificationInitialized = false;
							 | 
						|
								  
							 | 
						|
								  // ActiveDid change tracking
							 | 
						|
								  private currentActiveDid: string | null = null;
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // EXISTING CONSTRUCTOR (unchanged)
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  constructor() {
							 | 
						|
								    this.sqlite = new SQLiteConnection(CapacitorSQLite);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // MODIFIED METHOD: Enhanced updateActiveDid with DailyNotification Integration
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Enhanced updateActiveDid method that handles DailyNotification plugin updates
							 | 
						|
								   * 
							 | 
						|
								   * This method extends the existing updateActiveDid method to also update
							 | 
						|
								   * the DailyNotification plugin when the activeDid changes.
							 | 
						|
								   */
							 | 
						|
								  async updateActiveDid(did: string): Promise<void> {
							 | 
						|
								    const oldDid = this.currentActiveDid;
							 | 
						|
								    
							 | 
						|
								    // Update the database (existing TimeSafari pattern)
							 | 
						|
								    await this.dbExec(
							 | 
						|
								      "UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
							 | 
						|
								      [did],
							 | 
						|
								    );
							 | 
						|
								    
							 | 
						|
								    // Update local tracking
							 | 
						|
								    this.currentActiveDid = did;
							 | 
						|
								    
							 | 
						|
								    // Update DailyNotification plugin if initialized
							 | 
						|
								    if (this.dailyNotificationInitialized) {
							 | 
						|
								      await this.updateDailyNotificationActiveDid(did, oldDid);
							 | 
						|
								    }
							 | 
						|
								    
							 | 
						|
								    logger.debug(
							 | 
						|
								      `[CapacitorPlatformService] ActiveDid updated from ${oldDid} to ${did}`
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Update DailyNotification Plugin ActiveDid
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Update DailyNotification plugin when activeDid changes
							 | 
						|
								   */
							 | 
						|
								  private async updateDailyNotificationActiveDid(newDid: string, oldDid: string | null): Promise<void> {
							 | 
						|
								    try {
							 | 
						|
								      logger.log(`[CapacitorPlatformService] Updating DailyNotification plugin activeDid from ${oldDid} to ${newDid}`);
							 | 
						|
								      
							 | 
						|
								      // Get new settings for the new activeDid
							 | 
						|
								      const newSettings = await this.getTimeSafariSettings();
							 | 
						|
								      
							 | 
						|
								      // Reconfigure DailyNotification plugin with new activeDid
							 | 
						|
								      await DailyNotification.configure({
							 | 
						|
								        timesafariConfig: {
							 | 
						|
								          activeDid: newDid,
							 | 
						|
								          endpoints: {
							 | 
						|
								            offersToPerson: `${newSettings.apiServer}/api/v2/offers/person`,
							 | 
						|
								            offersToPlans: `${newSettings.apiServer}/api/v2/offers/plans`,
							 | 
						|
								            projectsLastUpdated: `${newSettings.apiServer}/api/v2/report/plansLastUpdatedBetween`
							 | 
						|
								          },
							 | 
						|
								          starredProjectsConfig: {
							 | 
						|
								            enabled: true,
							 | 
						|
								            starredPlanHandleIds: newSettings.starredPlanHandleIds || [],
							 | 
						|
								            lastAckedJwtId: newSettings.lastAckedStarredPlanChangesJwtId || '',
							 | 
						|
								            fetchInterval: '0 8 * * *'
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      });
							 | 
						|
								      
							 | 
						|
								      // Update TimeSafari Integration Service
							 | 
						|
								      if (this.integrationService) {
							 | 
						|
								        await this.integrationService.initialize({
							 | 
						|
								          activeDid: newDid,
							 | 
						|
								          storageAdapter: this.getTimeSafariStorageAdapter(),
							 | 
						|
								          endorserApiBaseUrl: newSettings.apiServer || 'https://endorser.ch'
							 | 
						|
								        });
							 | 
						|
								      }
							 | 
						|
								      
							 | 
						|
								      logger.log(`[CapacitorPlatformService] DailyNotification plugin updated successfully for activeDid: ${newDid}`);
							 | 
						|
								      
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error(`[CapacitorPlatformService] Failed to update DailyNotification plugin activeDid:`, error);
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Initialize DailyNotification Plugin
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Initialize DailyNotification plugin with TimeSafari configuration
							 | 
						|
								   */
							 | 
						|
								  async initializeDailyNotification(): Promise<void> {
							 | 
						|
								    if (this.dailyNotificationInitialized) {
							 | 
						|
								      return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    try {
							 | 
						|
								      logger.log("[CapacitorPlatformService] Initializing DailyNotification plugin...");
							 | 
						|
								      
							 | 
						|
								      // Get current TimeSafari settings
							 | 
						|
								      const settings = await this.getTimeSafariSettings();
							 | 
						|
								      
							 | 
						|
								      // Get current activeDid
							 | 
						|
								      const currentActiveDid = await this.getCurrentActiveDid();
							 | 
						|
								      
							 | 
						|
								      // Configure DailyNotification plugin with TimeSafari data
							 | 
						|
								      await DailyNotification.configure({
							 | 
						|
								        // Basic plugin configuration
							 | 
						|
								        storage: 'tiered',
							 | 
						|
								        ttlSeconds: 1800,
							 | 
						|
								        enableETagSupport: true,
							 | 
						|
								        enableErrorHandling: true,
							 | 
						|
								        enablePerformanceOptimization: true,
							 | 
						|
								        
							 | 
						|
								        // TimeSafari-specific configuration
							 | 
						|
								        timesafariConfig: {
							 | 
						|
								          // Use current activeDid
							 | 
						|
								          activeDid: currentActiveDid || '',
							 | 
						|
								          
							 | 
						|
								          // Use existing TimeSafari API endpoints
							 | 
						|
								          endpoints: {
							 | 
						|
								            offersToPerson: `${settings.apiServer}/api/v2/offers/person`,
							 | 
						|
								            offersToPlans: `${settings.apiServer}/api/v2/offers/plans`,
							 | 
						|
								            projectsLastUpdated: `${settings.apiServer}/api/v2/report/plansLastUpdatedBetween`
							 | 
						|
								          },
							 | 
						|
								          
							 | 
						|
								          // Configure starred projects fetching (matches existing TimeSafari pattern)
							 | 
						|
								          starredProjectsConfig: {
							 | 
						|
								            enabled: true,
							 | 
						|
								            starredPlanHandleIds: settings.starredPlanHandleIds || [],
							 | 
						|
								            lastAckedJwtId: settings.lastAckedStarredPlanChangesJwtId || '',
							 | 
						|
								            fetchInterval: '0 8 * * *',  // Daily at 8 AM
							 | 
						|
								            maxResults: 50,
							 | 
						|
								            hitLimitHandling: 'warn'  // Same as existing TimeSafari error handling
							 | 
						|
								          },
							 | 
						|
								          
							 | 
						|
								          // Sync configuration (optimized for TimeSafari use case)
							 | 
						|
								          syncConfig: {
							 | 
						|
								            enableParallel: true,
							 | 
						|
								            maxConcurrent: 3,
							 | 
						|
								            batchSize: 10,
							 | 
						|
								            timeout: 30000,
							 | 
						|
								            retryAttempts: 3
							 | 
						|
								          },
							 | 
						|
								          
							 | 
						|
								          // Error policy (matches existing TimeSafari error handling)
							 | 
						|
								          errorPolicy: {
							 | 
						|
								            maxRetries: 3,
							 | 
						|
								            backoffMultiplier: 2,
							 | 
						|
								            activeDidChangeRetries: 5,  // Special retry for activeDid changes
							 | 
						|
								            starredProjectsRetries: 3
							 | 
						|
								          }
							 | 
						|
								        },
							 | 
						|
								        
							 | 
						|
								        // Network configuration using existing TimeSafari patterns
							 | 
						|
								        networkConfig: {
							 | 
						|
								          baseURL: settings.apiServer || 'https://endorser.ch',
							 | 
						|
								          timeout: 30000,
							 | 
						|
								          retryAttempts: 3,
							 | 
						|
								          retryDelay: 1000,
							 | 
						|
								          maxConcurrent: 5,
							 | 
						|
								          
							 | 
						|
								          // Headers matching TimeSafari pattern
							 | 
						|
								          defaultHeaders: {
							 | 
						|
								            'Content-Type': 'application/json',
							 | 
						|
								            'Accept': 'application/json',
							 | 
						|
								            'User-Agent': 'TimeSafari-PWA/1.0.0'
							 | 
						|
								          }
							 | 
						|
								        },
							 | 
						|
								        
							 | 
						|
								        // Content fetch configuration (replaces existing loadNewStarredProjectChanges)
							 | 
						|
								        contentFetch: {
							 | 
						|
								          enabled: true,
							 | 
						|
								          schedule: '0 8 * * *',  // Daily at 8 AM
							 | 
						|
								          
							 | 
						|
								          // Use existing TimeSafari request pattern
							 | 
						|
								          requestConfig: {
							 | 
						|
								            method: 'POST',
							 | 
						|
								            url: `${settings.apiServer}/api/v2/report/plansLastUpdatedBetween`,
							 | 
						|
								            headers: {
							 | 
						|
								              'Authorization': 'Bearer ${jwt}',
							 | 
						|
								              'X-User-DID': '${activeDid}',
							 | 
						|
								              'Content-Type': 'application/json'
							 | 
						|
								            },
							 | 
						|
								            body: {
							 | 
						|
								              planIds: '${starredPlanHandleIds}',
							 | 
						|
								              afterId: '${lastAckedJwtId}'
							 | 
						|
								            }
							 | 
						|
								          },
							 | 
						|
								          
							 | 
						|
								          // Callbacks that match TimeSafari error handling
							 | 
						|
								          callbacks: {
							 | 
						|
								            onSuccess: this.handleStarredProjectsSuccess.bind(this),
							 | 
						|
								            onError: this.handleStarredProjectsError.bind(this),
							 | 
						|
								            onComplete: this.handleStarredProjectsComplete.bind(this)
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								      });
							 | 
						|
								      
							 | 
						|
								      // Initialize TimeSafari Integration Service
							 | 
						|
								      this.integrationService = TimeSafariIntegrationService.getInstance();
							 | 
						|
								      await this.integrationService.initialize({
							 | 
						|
								        activeDid: currentActiveDid || '',
							 | 
						|
								        storageAdapter: this.getTimeSafariStorageAdapter(),
							 | 
						|
								        endorserApiBaseUrl: settings.apiServer || 'https://endorser.ch',
							 | 
						|
								        
							 | 
						|
								        // Use existing TimeSafari request patterns
							 | 
						|
								        requestConfig: {
							 | 
						|
								          baseURL: settings.apiServer || 'https://endorser.ch',
							 | 
						|
								          timeout: 30000,
							 | 
						|
								          retryAttempts: 3
							 | 
						|
								        },
							 | 
						|
								        
							 | 
						|
								        // Configure starred projects fetching
							 | 
						|
								        starredProjectsConfig: {
							 | 
						|
								          enabled: true,
							 | 
						|
								          starredPlanHandleIds: settings.starredPlanHandleIds || [],
							 | 
						|
								          lastAckedJwtId: settings.lastAckedStarredPlanChangesJwtId || '',
							 | 
						|
								          fetchInterval: '0 8 * * *',
							 | 
						|
								          maxResults: 50
							 | 
						|
								        }
							 | 
						|
								      });
							 | 
						|
								      
							 | 
						|
								      // Schedule daily notifications
							 | 
						|
								      await DailyNotification.scheduleDailyNotification({
							 | 
						|
								        title: 'TimeSafari Community Update',
							 | 
						|
								        body: 'You have new offers and project updates',
							 | 
						|
								        time: '09:00',
							 | 
						|
								        channel: 'timesafari_community_updates'
							 | 
						|
								      });
							 | 
						|
								      
							 | 
						|
								      this.dailyNotificationInitialized = true;
							 | 
						|
								      this.currentActiveDid = currentActiveDid;
							 | 
						|
								      
							 | 
						|
								      logger.log("[CapacitorPlatformService] DailyNotification plugin initialized successfully");
							 | 
						|
								      
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error("[CapacitorPlatformService] Failed to initialize DailyNotification plugin:", error);
							 | 
						|
								      throw error;
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Get Current ActiveDid
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Get current activeDid from the database
							 | 
						|
								   */
							 | 
						|
								  private async getCurrentActiveDid(): Promise<string | null> {
							 | 
						|
								    try {
							 | 
						|
								      const result = await this.dbQuery(
							 | 
						|
								        "SELECT activeDid FROM active_identity WHERE id = 1"
							 | 
						|
								      );
							 | 
						|
								      
							 | 
						|
								      if (result?.values?.length) {
							 | 
						|
								        const activeDid = result.values[0][0] as string | null;
							 | 
						|
								        return activeDid;
							 | 
						|
								      }
							 | 
						|
								      
							 | 
						|
								      return null;
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error("[CapacitorPlatformService] Error getting current activeDid:", error);
							 | 
						|
								      return null;
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Enhanced loadNewStarredProjectChanges
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Enhanced version of existing TimeSafari loadNewStarredProjectChanges method
							 | 
						|
								   * 
							 | 
						|
								   * This method replaces the existing TimeSafari PWA method with plugin-enhanced
							 | 
						|
								   * functionality while maintaining the same interface and behavior.
							 | 
						|
								   */
							 | 
						|
								  async loadNewStarredProjectChanges(): Promise<StarredProjectsResponse> {
							 | 
						|
								    // Ensure DailyNotification is initialized
							 | 
						|
								    if (!this.dailyNotificationInitialized) {
							 | 
						|
								      await this.initializeDailyNotification();
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    const settings = await this.getTimeSafariSettings();
							 | 
						|
								    const currentActiveDid = await this.getCurrentActiveDid();
							 | 
						|
								    
							 | 
						|
								    if (!currentActiveDid || !settings.starredPlanHandleIds?.length) {
							 | 
						|
								      return { data: [], hitLimit: false };
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    try {
							 | 
						|
								      // Use plugin's enhanced fetching with same interface as existing TimeSafari code
							 | 
						|
								      const starredProjectChanges = await this.integrationService?.getStarredProjectsWithChanges(
							 | 
						|
								        currentActiveDid,
							 | 
						|
								        settings.starredPlanHandleIds,
							 | 
						|
								        settings.lastAckedStarredPlanChangesJwtId
							 | 
						|
								      );
							 | 
						|
								      
							 | 
						|
								      if (!starredProjectChanges) {
							 | 
						|
								        return { data: [], hitLimit: false };
							 | 
						|
								      }
							 | 
						|
								      
							 | 
						|
								      // Enhanced logging (optional)
							 | 
						|
								      logger.log("[CapacitorPlatformService] Starred projects loaded successfully:", {
							 | 
						|
								        count: starredProjectChanges.data.length,
							 | 
						|
								        hitLimit: starredProjectChanges.hitLimit,
							 | 
						|
								        planIds: settings.starredPlanHandleIds.length,
							 | 
						|
								        activeDid: currentActiveDid
							 | 
						|
								      });
							 | 
						|
								      
							 | 
						|
								      return starredProjectChanges;
							 | 
						|
								      
							 | 
						|
								    } catch (error) {
							 | 
						|
								      // Same error handling as existing TimeSafari code
							 | 
						|
								      logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error);
							 | 
						|
								      return { data: [], hitLimit: false };
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Get TimeSafari Settings
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Get TimeSafari settings using existing database patterns
							 | 
						|
								   */
							 | 
						|
								  private async getTimeSafariSettings(): Promise<TimeSafariSettings> {
							 | 
						|
								    try {
							 | 
						|
								      // Get current activeDid
							 | 
						|
								      const currentActiveDid = await this.getCurrentActiveDid();
							 | 
						|
								      
							 | 
						|
								      if (!currentActiveDid) {
							 | 
						|
								        return {};
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // Use existing TimeSafari settings retrieval pattern
							 | 
						|
								      const result = await this.dbQuery(
							 | 
						|
								        "SELECT * FROM settings WHERE accountDid = ?",
							 | 
						|
								        [currentActiveDid]
							 | 
						|
								      );
							 | 
						|
								      
							 | 
						|
								      if (!result?.values?.length) {
							 | 
						|
								        return {};
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      // Map database columns to values (existing TimeSafari pattern)
							 | 
						|
								      const settings: TimeSafariSettings = {};
							 | 
						|
								      result.columns.forEach((column, index) => {
							 | 
						|
								        if (column !== 'id') {
							 | 
						|
								          settings[column] = result.values[0][index];
							 | 
						|
								        }
							 | 
						|
								      });
							 | 
						|
								
							 | 
						|
								      // Set activeDid from current value
							 | 
						|
								      settings.activeDid = currentActiveDid;
							 | 
						|
								
							 | 
						|
								      // Handle JSON field parsing (existing TimeSafari pattern)
							 | 
						|
								      if (settings.starredPlanHandleIds && typeof settings.starredPlanHandleIds === 'string') {
							 | 
						|
								        try {
							 | 
						|
								          settings.starredPlanHandleIds = JSON.parse(settings.starredPlanHandleIds);
							 | 
						|
								        } catch {
							 | 
						|
								          settings.starredPlanHandleIds = [];
							 | 
						|
								        }
							 | 
						|
								      }
							 | 
						|
								
							 | 
						|
								      return settings;
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error("[CapacitorPlatformService] Error getting TimeSafari settings:", error);
							 | 
						|
								      return {};
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Get TimeSafari Storage Adapter
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Get TimeSafari storage adapter using existing patterns
							 | 
						|
								   */
							 | 
						|
								  private getTimeSafariStorageAdapter(): unknown {
							 | 
						|
								    // Return existing TimeSafari storage adapter
							 | 
						|
								    return {
							 | 
						|
								      // Use existing TimeSafari storage patterns
							 | 
						|
								      store: async (key: string, value: unknown): Promise<void> => {
							 | 
						|
								        await this.dbExec(
							 | 
						|
								          "INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
							 | 
						|
								          [key, JSON.stringify(value)]
							 | 
						|
								        );
							 | 
						|
								      },
							 | 
						|
								      
							 | 
						|
								      retrieve: async (key: string): Promise<unknown> => {
							 | 
						|
								        const result = await this.dbQuery(
							 | 
						|
								          "SELECT data FROM temp WHERE id = ?",
							 | 
						|
								          [key]
							 | 
						|
								        );
							 | 
						|
								        
							 | 
						|
								        if (result?.values?.length) {
							 | 
						|
								          try {
							 | 
						|
								            return JSON.parse(result.values[0][0] as string);
							 | 
						|
								          } catch {
							 | 
						|
								            return null;
							 | 
						|
								          }
							 | 
						|
								        }
							 | 
						|
								        
							 | 
						|
								        return null;
							 | 
						|
								      }
							 | 
						|
								    };
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHODS: Callback Handlers
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Callback handler for successful starred projects fetch
							 | 
						|
								   */
							 | 
						|
								  private async handleStarredProjectsSuccess(data: StarredProjectsResponse): Promise<void> {
							 | 
						|
								    // Enhanced logging (optional)
							 | 
						|
								    logger.log("[CapacitorPlatformService] Starred projects success callback:", {
							 | 
						|
								      count: data.data.length,
							 | 
						|
								      hitLimit: data.hitLimit,
							 | 
						|
								      activeDid: this.currentActiveDid
							 | 
						|
								    });
							 | 
						|
								    
							 | 
						|
								    // Store results in TimeSafari temp table for UI access
							 | 
						|
								    await this.dbExec(
							 | 
						|
								      "INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
							 | 
						|
								      ['starred_projects_latest', JSON.stringify(data)]
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Callback handler for starred projects fetch errors
							 | 
						|
								   */
							 | 
						|
								  private async handleStarredProjectsError(error: Error): Promise<void> {
							 | 
						|
								    // Same error handling as existing TimeSafari code
							 | 
						|
								    logger.warn("[CapacitorPlatformService] Failed to load starred project changes:", error);
							 | 
						|
								    
							 | 
						|
								    // Store error in TimeSafari temp table for UI access
							 | 
						|
								    await this.dbExec(
							 | 
						|
								      "INSERT OR REPLACE INTO temp (id, data) VALUES (?, ?)",
							 | 
						|
								      ['starred_projects_error', JSON.stringify({ 
							 | 
						|
								        error: error.message, 
							 | 
						|
								        timestamp: Date.now(),
							 | 
						|
								        activeDid: this.currentActiveDid
							 | 
						|
								      })]
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Callback handler for starred projects fetch completion
							 | 
						|
								   */
							 | 
						|
								  private async handleStarredProjectsComplete(result: unknown): Promise<void> {
							 | 
						|
								    // Handle completion
							 | 
						|
								    logger.log("[CapacitorPlatformService] Starred projects fetch completed:", {
							 | 
						|
								      result,
							 | 
						|
								      activeDid: this.currentActiveDid
							 | 
						|
								    });
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // NEW METHOD: Get DailyNotification Status
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Get DailyNotification plugin status for debugging
							 | 
						|
								   */
							 | 
						|
								  async getDailyNotificationStatus(): Promise<{
							 | 
						|
								    initialized: boolean;
							 | 
						|
								    platform: string;
							 | 
						|
								    capabilities: PlatformCapabilities;
							 | 
						|
								    currentActiveDid: string | null;
							 | 
						|
								  }> {
							 | 
						|
								    return {
							 | 
						|
								      initialized: this.dailyNotificationInitialized,
							 | 
						|
								      platform: Capacitor.getPlatform(),
							 | 
						|
								      capabilities: this.getCapabilities(),
							 | 
						|
								      currentActiveDid: this.currentActiveDid
							 | 
						|
								    };
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // MODIFIED METHOD: Enhanced initializeDatabase
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  private async initializeDatabase(): Promise<void> {
							 | 
						|
								    // If already initialized, return immediately
							 | 
						|
								    if (this.initialized) {
							 | 
						|
								      return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    // If initialization is in progress, wait for it
							 | 
						|
								    if (this.initializationPromise) {
							 | 
						|
								      return this.initializationPromise;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    try {
							 | 
						|
								      // Start initialization
							 | 
						|
								      this.initializationPromise = this._initialize();
							 | 
						|
								      await this.initializationPromise;
							 | 
						|
								      
							 | 
						|
								      // NEW: Initialize DailyNotification after database is ready
							 | 
						|
								      await this.initializeDailyNotification();
							 | 
						|
								      
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error(
							 | 
						|
								        "[CapacitorPlatformService] Initialize database method failed:",
							 | 
						|
								        error,
							 | 
						|
								      );
							 | 
						|
								      this.initializationPromise = null; // Reset on failure
							 | 
						|
								      throw error;
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // =================================================
							 | 
						|
								  // EXISTING METHODS (unchanged - showing key ones)
							 | 
						|
								  // =================================================
							 | 
						|
								  
							 | 
						|
								  private async _initialize(): Promise<void> {
							 | 
						|
								    if (this.initialized) {
							 | 
						|
								      return;
							 | 
						|
								    }
							 | 
						|
								
							 | 
						|
								    try {
							 | 
						|
								      // Create/Open database
							 | 
						|
								      this.db = await this.sqlite.createConnection(
							 | 
						|
								        this.dbName,
							 | 
						|
								        false,
							 | 
						|
								        "no-encryption",
							 | 
						|
								        1,
							 | 
						|
								        false,
							 | 
						|
								      );
							 | 
						|
								
							 | 
						|
								      await this.db.open();
							 | 
						|
								
							 | 
						|
								      // Run migrations
							 | 
						|
								      await this.runCapacitorMigrations();
							 | 
						|
								
							 | 
						|
								      this.initialized = true;
							 | 
						|
								      logger.log(
							 | 
						|
								        "[CapacitorPlatformService] SQLite database initialized successfully",
							 | 
						|
								      );
							 | 
						|
								
							 | 
						|
								      // Start processing the queue after initialization
							 | 
						|
								      this.processQueue();
							 | 
						|
								    } catch (error) {
							 | 
						|
								      logger.error(
							 | 
						|
								        "[CapacitorPlatformService] Error initializing SQLite database:",
							 | 
						|
								        error,
							 | 
						|
								      );
							 | 
						|
								      throw new Error(
							 | 
						|
								        "[CapacitorPlatformService] Failed to initialize database",
							 | 
						|
								      );
							 | 
						|
								    }
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // ... (all other existing methods remain unchanged)
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Gets the capabilities of the Capacitor platform
							 | 
						|
								   * @returns Platform capabilities object
							 | 
						|
								   */
							 | 
						|
								  getCapabilities(): PlatformCapabilities {
							 | 
						|
								    const platform = Capacitor.getPlatform();
							 | 
						|
								
							 | 
						|
								    return {
							 | 
						|
								      hasFileSystem: true,
							 | 
						|
								      hasCamera: true,
							 | 
						|
								      isMobile: true, // Capacitor is always mobile
							 | 
						|
								      isIOS: platform === "ios",
							 | 
						|
								      hasFileDownload: false, // Mobile platforms need sharing
							 | 
						|
								      needsFileHandlingInstructions: true, // Mobile needs instructions
							 | 
						|
								      isNativeApp: true,
							 | 
						|
								    };
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * @see PlatformService.dbQuery
							 | 
						|
								   */
							 | 
						|
								  async dbQuery(sql: string, params?: unknown[]): Promise<QueryExecResult> {
							 | 
						|
								    await this.waitForInitialization();
							 | 
						|
								    return this.queueOperation<QueryExecResult>("query", sql, params || []);
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * @see PlatformService.dbExec
							 | 
						|
								   */
							 | 
						|
								  async dbExec(
							 | 
						|
								    sql: string,
							 | 
						|
								    params?: unknown[],
							 | 
						|
								  ): Promise<{ changes: number; lastId?: number }> {
							 | 
						|
								    await this.waitForInitialization();
							 | 
						|
								    return this.queueOperation<{ changes: number; lastId?: number }>(
							 | 
						|
								      "run",
							 | 
						|
								      sql,
							 | 
						|
								      params || [],
							 | 
						|
								    );
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // ... (all other existing methods remain unchanged)
							 | 
						|
								  
							 | 
						|
								  /**
							 | 
						|
								   * Checks if running on Capacitor platform.
							 | 
						|
								   * @returns true, as this is the Capacitor implementation
							 | 
						|
								   */
							 | 
						|
								  isCapacitor(): boolean {
							 | 
						|
								    return true;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Checks if running on Electron platform.
							 | 
						|
								   * @returns false, as this is Capacitor, not Electron
							 | 
						|
								   */
							 | 
						|
								  isElectron(): boolean {
							 | 
						|
								    return false;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  /**
							 | 
						|
								   * Checks if running on web platform.
							 | 
						|
								   * @returns false, as this is not web
							 | 
						|
								   */
							 | 
						|
								  isWeb(): boolean {
							 | 
						|
								    return false;
							 | 
						|
								  }
							 | 
						|
								
							 | 
						|
								  // ... (all other existing methods remain unchanged)
							 | 
						|
								}
							 | 
						|
								
							 |