nexabase_flutter_sdk 1.0.5 copy "nexabase_flutter_sdk: ^1.0.5" to clipboard
nexabase_flutter_sdk: ^1.0.5 copied to clipboard

SDK oficial de Flutter para Nexabase - Base de datos en tiempo real para aplicaciones Flutter

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:nexabase_flutter_sdk/nexabase_flutter_sdk.dart';
import 'dart:typed_data';

void main() {
  runApp(const NexabaseExampleApp());
}

class NexabaseExampleApp extends StatelessWidget {
  const NexabaseExampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Nexabase SDK Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        useMaterial3: true,
      ),
      home: const HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  bool _isInitialized = false;
  bool _isLoading = false;
  String _status = 'Inicializando...';
  List<NexabaseRecord> _records = [];
  NexabaseUser? _currentUser;
  String _selectedCollection = 'usuarios';

  @override
  void initState() {
    super.initState();
    _initializeNexabase();
  }

  Future<void> _initializeNexabase() async {
    setState(() {
      _isLoading = true;
      _status = 'Conectando a Nexabase...';
    });

    try {
      // Inicializar el cliente
      await NexabaseClient.instance.initialize(
        AuthConfig(
          baseUrl: 'http://localhost:3000', // Cambia por tu URL
          apiKey:
              'nxb_7550817293880fcfa8b4851f0903804aac684eed185c719e39645e6d25eb1d01', // Cambia por tu API key
          enableDebugLogs: true,
        ),
      );

      setState(() {
        _isInitialized = true;
        _status = '✅ Conectado a Nexabase';
      });

      // Escuchar cambios de autenticación
      NexabaseClient.instance.auth.authStateChanges.listen((authState) {
        setState(() {
          _currentUser = authState.user;
          if (authState.isAuthenticated) {
            _status = '✅ Usuario autenticado: ${authState.user?.email}';
          } else {
            _status = '⚠️ Usuario no autenticado';
          }
        });
      });

      // Cargar datos iniciales
      await _loadRecords();
    } catch (e) {
      setState(() {
        _status = '❌ Error: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _authenticateUser() async {
    setState(() {
      _isLoading = true;
      _status = 'Autenticando usuario...';
    });

    try {
      // Intenta hacer login o registro
      final user = await NexabaseClient.instance.auth.login(
        email: 'demo@ejemplo.com',
        password: 'password123',
      );

      setState(() {
        _currentUser = user;
        _status = '✅ Usuario autenticado: ${user.email}';
      });
    } catch (e) {
      // Si falla el login, intentar registro
      try {
        final user = await NexabaseClient.instance.auth.register(
          email: 'demo@ejemplo.com',
          password: 'password123',
          firstName: 'Demo',
          lastName: 'User',
        );

        setState(() {
          _currentUser = user;
          _status = '✅ Usuario registrado: ${user.email}';
        });
      } catch (registerError) {
        setState(() {
          _status = '❌ Error de autenticación: $registerError';
        });
      }
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _loadRecords() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Cargando registros de $_selectedCollection...';
    });

    try {
      final response = await NexabaseClient.instance.database.getRecords(
        _selectedCollection,
        options: QueryOptions(
          limit: 10,
          orderBy: 'created_at',
          order: SortDirection.desc,
        ),
      );

      setState(() {
        _records = response.records;
        _status =
            '✅ ${response.records.length} registros cargados de $_selectedCollection';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al cargar registros: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _loadRecordsAdvanced() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Cargando registros avanzados de $_selectedCollection...';
    });

    try {
      final response =
          await NexabaseClient.instance.database.getRecordsAdvanced(
        _selectedCollection,
        page: 1,
        limit: 10,
        search: 'demo',
        filters: [
          CollectionFilter(
            field: 'activo',
            operator: FilterOperator.equals,
            value: true,
          ),
        ],
        sort: [
          CollectionSort(
            field: 'created_at',
            direction: SortDirection.desc,
          ),
        ],
      );

      setState(() {
        _records = response.records;
        _status = '✅ ${response.records.length} registros avanzados cargados';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al cargar registros avanzados: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _createRecord() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Creando registro en $_selectedCollection...';
    });

    try {
      final newRecord = await NexabaseClient.instance.database.createRecord(
        _selectedCollection,
        {
          'nombre': 'Usuario Demo ${DateTime.now().millisecondsSinceEpoch}',
          'email': 'demo${DateTime.now().millisecondsSinceEpoch}@ejemplo.com',
          'activo': true,
          'metadata': {
            'source': 'flutter_sdk_demo',
            'timestamp': DateTime.now().toIso8601String(),
          },
        },
      );

      setState(() {
        _records.insert(0, newRecord);
        _status = '✅ Registro creado: ${newRecord.id}';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al crear registro: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _startRealtimeSubscription() async {
    if (!_isInitialized) return;

    try {
      // Habilitar tiempo real para la colección
      await NexabaseClient.instance.realtime
          .enableRealtimeForCollection(_selectedCollection);

      // Conectar al servicio de tiempo real
      await NexabaseClient.instance.realtime.connect();

      // Suscribirse a cambios en tiempo real
      NexabaseClient.instance.realtime.subscribe(_selectedCollection).listen(
        (event) {
          setState(() {
            _status =
                '🔄 Evento en tiempo real: ${event.type.name} en ${event.collection}';
          });

          // Recargar datos cuando hay cambios
          _loadRecords();
        },
        onError: (error) {
          setState(() {
            _status = '❌ Error en tiempo real: $error';
          });
        },
      );

      setState(() {
        _status =
            '📡 Suscrito a cambios en tiempo real para $_selectedCollection';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al configurar tiempo real: $e';
      });
    }
  }

  Future<void> _testStorageUpload() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Probando subida de archivo...';
    });

    try {
      // Crear un archivo de prueba
      final testData =
          'Contenido de prueba desde Flutter SDK - ${DateTime.now()}';
      final bytes = Uint8List.fromList(testData.codeUnits);

      final uploadedFile = await NexabaseClient.instance.storage.uploadBytes(
        bytes: bytes,
        fileName: 'test_flutter_sdk.txt',
        mimeType: 'text/plain',
        folder: 'demo',
      );

      setState(() {
        _status =
            '✅ Archivo subido: ${uploadedFile.originalName} (${uploadedFile.sizeFormatted})';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al subir archivo: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _getStorageStats() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Obteniendo estadísticas de almacenamiento...';
    });

    try {
      final usage = await NexabaseClient.instance.storage.getTenantUsage();

      setState(() {
        _status =
            '📊 Storage: ${usage.storage.usedGb.toStringAsFixed(2)}GB/${usage.storage.limitGb}GB (${usage.storage.usagePercentage.toStringAsFixed(1)}%)';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al obtener estadísticas: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _getRealtimeStats() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Obteniendo estadísticas de tiempo real...';
    });

    try {
      final stats = await NexabaseClient.instance.realtime.getStats();

      setState(() {
        _status =
            '📊 Tiempo Real: ${stats.totalConnections} conexiones, ${stats.activeCollections} colecciones activas';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al obtener estadísticas de tiempo real: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  Future<void> _checkHealth() async {
    if (!_isInitialized) return;

    setState(() {
      _isLoading = true;
      _status = 'Verificando salud del sistema...';
    });

    try {
      final health = await NexabaseClient.instance.checkHealth();

      setState(() {
        _status =
            '🏥 Salud: ${health.isHealthy ? "✅ Saludable" : "❌ Con problemas"} - ${health.responseTime.inMilliseconds}ms';
      });
    } catch (e) {
      setState(() {
        _status = '❌ Error al verificar salud: $e';
      });
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Nexabase SDK Demo'),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            // Estado actual
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Estado de Conexión',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    Text(_status),
                    if (_currentUser != null) ...[
                      const SizedBox(height: 8),
                      Text(
                          'Usuario: ${_currentUser!.fullName} (${_currentUser!.role})'),
                    ],
                    if (_isLoading) ...[
                      const SizedBox(height: 8),
                      const LinearProgressIndicator(),
                    ],
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Selector de colección
            Card(
              child: Padding(
                padding: const EdgeInsets.all(16.0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Colección',
                      style: Theme.of(context).textTheme.titleMedium,
                    ),
                    const SizedBox(height: 8),
                    DropdownButton<String>(
                      value: _selectedCollection,
                      isExpanded: true,
                      items: const [
                        DropdownMenuItem(
                            value: 'usuarios', child: Text('usuarios')),
                        DropdownMenuItem(
                            value: 'productos', child: Text('productos')),
                        DropdownMenuItem(
                            value: 'pedidos', child: Text('pedidos')),
                      ],
                      onChanged: (value) {
                        if (value != null) {
                          setState(() {
                            _selectedCollection = value;
                          });
                          _loadRecords();
                        }
                      },
                    ),
                  ],
                ),
              ),
            ),

            const SizedBox(height: 16),

            // Botones de acción - Fila 1
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _authenticateUser : null,
                  child: const Text('Autenticar'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _loadRecords : null,
                  child: const Text('Cargar'),
                ),
                ElevatedButton(
                  onPressed: _isInitialized && !_isLoading
                      ? _loadRecordsAdvanced
                      : null,
                  child: const Text('Avanzado'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _createRecord : null,
                  child: const Text('Crear'),
                ),
              ],
            ),

            const SizedBox(height: 8),

            // Botones de acción - Fila 2
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                ElevatedButton(
                  onPressed: _isInitialized ? _startRealtimeSubscription : null,
                  child: const Text('Tiempo Real'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _testStorageUpload : null,
                  child: const Text('Upload'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _getStorageStats : null,
                  child: const Text('Storage'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _getRealtimeStats : null,
                  child: const Text('RT Stats'),
                ),
                ElevatedButton(
                  onPressed:
                      _isInitialized && !_isLoading ? _checkHealth : null,
                  child: const Text('Salud'),
                ),
              ],
            ),

            const SizedBox(height: 16),

            // Lista de registros
            Expanded(
              child: Card(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Padding(
                      padding: const EdgeInsets.all(16.0),
                      child: Text(
                        'Registros de $_selectedCollection (${_records.length})',
                        style: Theme.of(context).textTheme.titleMedium,
                      ),
                    ),
                    Expanded(
                      child: _records.isEmpty
                          ? const Center(
                              child: Text('No hay registros para mostrar'),
                            )
                          : ListView.builder(
                              itemCount: _records.length,
                              itemBuilder: (context, index) {
                                final record = _records[index];
                                return ListTile(
                                  title: Text(
                                      record.getValue<String>('nombre') ??
                                          record.getValue<String>('name') ??
                                          'Sin nombre'),
                                  subtitle: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Text('ID: ${record.id}'),
                                      if (record.getValue<String>('email') !=
                                          null)
                                        Text(
                                            'Email: ${record.getValue<String>('email')}'),
                                      if (record.createdAt != null)
                                        Text(
                                            'Creado: ${record.createdAt!.toLocal().toString().split('.').first}'),
                                    ],
                                  ),
                                  trailing:
                                      record.getValue<bool>('activo') == true
                                          ? const Icon(Icons.check_circle,
                                              color: Colors.green)
                                          : const Icon(Icons.cancel,
                                              color: Colors.red),
                                  isThreeLine: true,
                                );
                              },
                            ),
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void dispose() {
    // Limpiar recursos al cerrar la app
    NexabaseClient.instance.dispose();
    super.dispose();
  }
}
0
likes
135
points
14
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

SDK oficial de Flutter para Nexabase - Base de datos en tiempo real para aplicaciones Flutter

Homepage

License

MIT (license)

Dependencies

crypto, dio, flutter, http, json_annotation, logger, shared_preferences, web_socket_channel

More

Packages that depend on nexabase_flutter_sdk