UNPKG

react-native-healthkit-bridge

Version:

A comprehensive React Native bridge for Apple HealthKit with TypeScript support, advanced authorization, and flexible data queries

358 lines (357 loc) 16.1 kB
import { HEALTHKIT_CONFIG } from '../../config/healthkit.config'; import { HealthKitValidator } from '../../utils/ValidationUtils'; import { HealthKitErrorHandler } from '../../utils/ErrorHandler'; export class MockProvider { constructor(config = {}) { this.config = Object.assign({ mockDelay: HEALTHKIT_CONFIG.MOCK_DELAY, authorizationChance: HEALTHKIT_CONFIG.AUTHORIZATION_CHANCE }, config); this.mockDelay = this.config.mockDelay || HEALTHKIT_CONFIG.MOCK_DELAY; this.authorizationChance = this.config.authorizationChance || HEALTHKIT_CONFIG.AUTHORIZATION_CHANCE; } async simulateDelay() { await new Promise(resolve => setTimeout(resolve, this.mockDelay)); } generateMockQuantityData(identifier, days) { const mockData = []; for (let i = 0; i < days; i++) { switch (identifier) { case 'stepCount': mockData.push(Math.floor(Math.random() * 5000) + 2000); break; case 'distanceWalkingRunning': mockData.push(Math.floor(Math.random() * 5000) + 1000); break; case 'activeEnergyBurned': mockData.push(Math.floor(Math.random() * 300) + 100); break; case 'heartRate': mockData.push(Math.floor(Math.random() * 40) + 60); break; case 'bodyMass': mockData.push(Math.floor(Math.random() * 20) + 60); break; case 'height': mockData.push(Math.floor(Math.random() * 50) + 150); break; case 'flightsClimbed': mockData.push(Math.floor(Math.random() * 10) + 1); break; case 'appleExerciseTime': mockData.push(Math.floor(Math.random() * 60) + 10); // minutos break; default: mockData.push(Math.floor(Math.random() * 100)); } } return mockData; } generateMockWorkouts(days) { const workouts = []; const workoutTypes = [3, 7, 37]; // Running, Walking, Swimming const workoutCount = Math.min(Math.floor(days / 3), 10); for (let i = 0; i < workoutCount; i++) { workouts.push({ startDate: (Date.now() / 1000) - (i * 86400), endDate: (Date.now() / 1000) - (i * 86400) + 3600, activityType: workoutTypes[Math.floor(Math.random() * workoutTypes.length)], duration: Math.floor(Math.random() * 3600) + 1800, totalEnergyBurned: Math.floor(Math.random() * 500) + 200 }); } return workouts; } async requestAuthorization() { return HealthKitErrorHandler.withErrorHandling(async () => { await this.simulateDelay(); console.log('Mock: Autorização solicitada'); const authorized = Math.random() < this.authorizationChance; console.log(`Mock: Autorização ${authorized ? 'concedida' : 'negada'}`); return authorized; }, 'MockProvider.requestAuthorization', false); } async requestSelectiveAuthorization(identifiers) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateAuthorizationRequest(identifiers)) { throw new Error('Identificadores inválidos para autorização'); } await this.simulateDelay(); console.log(`Mock: Autorizando tipos seletivos: ${identifiers.join(', ')}`); const authorized = Math.random() < this.authorizationChance; console.log(`Mock: Autorização seletiva ${authorized ? 'concedida' : 'negada'}`); return authorized; }, 'MockProvider.requestSelectiveAuthorization', false); } async getAuthorizationStatus(identifiers) { return HealthKitErrorHandler.withErrorHandling(async () => { console.log('🔍 MockProvider.getAuthorizationStatus - Identificadores recebidos:', identifiers); // Validação mais flexível if (!identifiers || !Array.isArray(identifiers) || identifiers.length === 0) { console.warn('⚠️ Identificadores inválidos, retornando array vazio'); return []; } await this.simulateDelay(); console.log(`Mock: Verificando status para tipos: ${identifiers.join(', ')}`); return identifiers.map(identifier => ({ identifier, status: Math.random() > 0.3 ? 'sharingAuthorized' : 'sharingDenied' })); }, 'MockProvider.getAuthorizationStatus', []); } async getAvailableTypes() { return HealthKitErrorHandler.withErrorHandling(async () => { await this.simulateDelay(); console.log('Mock: Obtendo tipos disponíveis'); return [ { identifier: 'stepCount', name: 'Passos', description: 'Número de passos dados', category: 'activity', type: 'quantity' }, { identifier: 'distanceWalkingRunning', name: 'Distância', description: 'Distância caminhada/corrida', category: 'activity', type: 'quantity' }, { identifier: 'activeEnergyBurned', name: 'Calorias Ativas', description: 'Calorias queimadas em atividade', category: 'activity', type: 'quantity' }, { identifier: 'heartRate', name: 'Frequência Cardíaca', description: 'Batimentos por minuto', category: 'heart', type: 'quantity' }, { identifier: 'bodyMass', name: 'Peso', description: 'Peso corporal', category: 'body', type: 'quantity' }, { identifier: 'height', name: 'Altura', description: 'Altura corporal', category: 'body', type: 'quantity' }, { identifier: 'flightsClimbed', name: 'Lances de Escada', description: 'Número de lances de escada subidos', category: 'activity', type: 'quantity' }, { identifier: 'appleExerciseTime', name: 'Tempo de Exercício', description: 'Tempo de exercício ativo', category: 'activity', type: 'quantity' } ]; }, 'MockProvider.getAvailableTypes', []); } async getTypeInfo(identifier) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateIdentifier(identifier)) { throw new Error('Identificador inválido'); } await this.simulateDelay(); console.log(`Mock: Obtendo info para tipo ${identifier}`); return { identifier, name: identifier.charAt(0).toUpperCase() + identifier.slice(1), description: `Informações sobre ${identifier}`, category: 'activity', type: 'quantity', unit: HEALTHKIT_CONFIG.DEFAULT_UNITS[identifier] || 'count', permissions: { read: true, write: false } }; }, 'MockProvider.getTypeInfo', {}); } async getQuantitySamplesForDays(identifier, unit, days) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateIdentifier(identifier) || !HealthKitValidator.validateUnit(unit) || !HealthKitValidator.validateDays(days)) { throw new Error('Parâmetros inválidos para query de quantidade'); } await this.simulateDelay(); console.log(`Mock: Obtendo ${identifier} para ${days} dias`); return this.generateMockQuantityData(identifier, days); }, 'MockProvider.getQuantitySamplesForDays', []); } async getCategorySamplesForDays(identifier, days) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateIdentifier(identifier) || !HealthKitValidator.validateDays(days)) { throw new Error('Parâmetros inválidos para query de categoria'); } await this.simulateDelay(); console.log(`Mock: Obtendo dados categóricos ${identifier} para ${days} dias`); return []; }, 'MockProvider.getCategorySamplesForDays', []); } async getWorkoutsForDays(days) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateDays(days)) { throw new Error('Parâmetros inválidos para query de workouts'); } await this.simulateDelay(); console.log(`Mock: Obtendo workouts para ${days} dias`); return this.generateMockWorkouts(days); }, 'MockProvider.getWorkoutsForDays', []); } async getAudiogramsForDays(days) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateDays(days)) { throw new Error('Parâmetros inválidos para query de audiogramas'); } await this.simulateDelay(); console.log(`Mock: Obtendo audiogramas para ${days} dias`); return []; }, 'MockProvider.getAudiogramsForDays', []); } async getECGForDays(days) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateDays(days)) { throw new Error('Parâmetros inválidos para query de ECG'); } await this.simulateDelay(); console.log(`Mock: Obtendo ECG para ${days} dias`); return []; }, 'MockProvider.getECGForDays', []); } async getQuantitySamplesWithRange(identifier, unit, startDate, endDate) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateIdentifier(identifier) || !HealthKitValidator.validateUnit(unit)) { throw new Error('Parâmetros inválidos para query de quantidade com range'); } await this.simulateDelay(); console.log(`Mock: Obtendo ${identifier} com range`); const days = Math.ceil((endDate - startDate) / 86400); return this.generateMockQuantityData(identifier, days); }, 'MockProvider.getQuantitySamplesWithRange', []); } async getCategorySamplesWithRange(identifier, startDate, endDate) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateIdentifier(identifier)) { throw new Error('Parâmetros inválidos para query de categoria com range'); } await this.simulateDelay(); console.log(`Mock: Obtendo dados categóricos ${identifier} com range`); return []; }, 'MockProvider.getCategorySamplesWithRange', []); } async getWorkoutsWithRange(startDate, endDate) { return HealthKitErrorHandler.withErrorHandling(async () => { await this.simulateDelay(); console.log('Mock: Obtendo workouts com range'); const days = Math.ceil((endDate - startDate) / 86400); return this.generateMockWorkouts(days); }, 'MockProvider.getWorkoutsWithRange', []); } async getAudiogramsWithRange(startDate, endDate) { return HealthKitErrorHandler.withErrorHandling(async () => { await this.simulateDelay(); console.log('Mock: Obtendo audiogramas com range'); return []; }, 'MockProvider.getAudiogramsWithRange', []); } async getECGWithRange(startDate, endDate) { return HealthKitErrorHandler.withErrorHandling(async () => { await this.simulateDelay(); console.log('Mock: Obtendo ECG com range'); return []; }, 'MockProvider.getECGWithRange', []); } async getQuantitySamples(identifier, unit) { return this.getQuantitySamplesForDays(identifier, unit, HEALTHKIT_CONFIG.DEFAULT_DAYS); } async getCategorySamples(identifier) { return this.getCategorySamplesForDays(identifier, HEALTHKIT_CONFIG.DEFAULT_DAYS); } async getWorkoutsGeneric() { return this.getWorkoutsForDays(HEALTHKIT_CONFIG.DEFAULT_DAYS); } async getAudiograms() { return this.getAudiogramsForDays(HEALTHKIT_CONFIG.DEFAULT_DAYS); } async getECG() { return this.getECGForDays(HEALTHKIT_CONFIG.DEFAULT_DAYS); } // Métodos avançados (implementação básica para mock) async queryQuantitySamples(identifier, unit, options) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateQueryOptions(options)) { throw new Error('Opções de query inválidas'); } await this.simulateDelay(); console.log(`Mock: Query avançada para ${identifier}`); const days = options.days || HEALTHKIT_CONFIG.DEFAULT_DAYS; const data = this.generateMockQuantityData(identifier, days); return { data: data.map((value, index) => ({ value, unit, startDate: Date.now() / 1000 - (index * 86400), endDate: Date.now() / 1000 - (index * 86400) + 86400 })), count: data.length, hasMore: false }; }, 'MockProvider.queryQuantitySamples', { data: [], count: 0, hasMore: false }); } async queryCategorySamples(identifier, options) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateQueryOptions(options)) { throw new Error('Opções de query inválidas'); } await this.simulateDelay(); console.log(`Mock: Query avançada para categoria ${identifier}`); return { data: [], count: 0, hasMore: false }; }, 'MockProvider.queryCategorySamples', { data: [], count: 0, hasMore: false }); } async queryWorkouts(options) { return HealthKitErrorHandler.withErrorHandling(async () => { if (!HealthKitValidator.validateQueryOptions(options)) { throw new Error('Opções de query inválidas'); } await this.simulateDelay(); console.log('Mock: Query avançada para workouts'); const days = options.days || HEALTHKIT_CONFIG.DEFAULT_DAYS; const data = this.generateMockWorkouts(days); return { data, count: data.length, hasMore: false }; }, 'MockProvider.queryWorkouts', { data: [], count: 0, hasMore: false }); } isAvailable() { return true; // Mock sempre disponível } getProviderName() { return 'MockProvider'; } getProviderVersion() { return '1.0.0'; } }