nrb 4.0.3 copy "nrb: ^4.0.3" to clipboard
nrb: ^4.0.3 copied to clipboard

A highly responsive Flutter table and report builder for complex nested headers, editable data grids, and premium Excel/PDF exports.

example/lib/main.dart

import 'dart:io' show Directory, File, Platform;
import 'dart:typed_data';

import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/material.dart';

// Ensure your package is correctly imported
import 'package:nrb/nrb.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:device_info_plus/device_info_plus.dart';

void main() {
  runApp(
    const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: NRBPackageDemoScreen(),
    ),
  );
}

/// This is a comprehensive showcase of the Nexora Report Builder (NRB) package.
///
/// It demonstrates how to integrate individual components (like Charts and Metrics)
/// alongside complex, interactive, and exportable Data Grids (NrbTableEngine).
class NRBPackageDemoScreen extends StatefulWidget {
  const NRBPackageDemoScreen({super.key});

  @override
  State<NRBPackageDemoScreen> createState() => _NRBPackageDemoScreenState();
}

class _NRBPackageDemoScreenState extends State<NRBPackageDemoScreen> {
  // --- BRAND COLORS ---
  final Color _primaryBrandColor = const Color(0xFF0B7A3E);
  final Color _secondaryBrandColor = const Color(0xFF1E88E5);

  // ===========================================================================
  // EXAMPLE 1: FINANCIAL REPORT DATA (Exportable Grid)
  // ===========================================================================
  /// [headers] define the column structure. Notice the use of `rowSpan` and
  /// `colSpan` to create complex, grouped HTML-style table headers.
  final List<List<NrbHeaderCell>> _financialHeaders = [
    [
      const NrbHeaderCell(
          text: "Region",
          colSpan: 1,
          rowSpan: 2,
          backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "Q4 Financials (USD)",
          colSpan: 3,
          backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "Operations",
          colSpan: 2,
          backgroundColor: Color(0xFF0B7A3E)),
    ],
    [
      const NrbHeaderCell(
          text: "Target Rev.", backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "Actual Rev.", backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "Margin %", backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "Active Clients", backgroundColor: Color(0xFF0B7A3E)),
      const NrbHeaderCell(
          text: "SLA Uptime", backgroundColor: Color(0xFF0B7A3E)),
    ]
  ];

  /// [tableData] contains the actual rows. Every element must be a `ReportCell`.
  /// Here we use `TextCell` which supports automatic text formatting.
  final List<List<ReportCell>> _financialData = [
    [
      const TextCell(
          itemContent: "North America", textAlignment: Alignment.centerLeft),
      const TextCell(itemContent: "1200000", isAmount: true), // Formats automatically
      const TextCell(itemContent: "1350000", isAmount: true),
      const TextCell(itemContent: "28%"),
      const TextCell(itemContent: "145"),
      const TextCell(itemContent: "99.99%"),
    ],
    [
      const TextCell(
          itemContent: "Europe", textAlignment: Alignment.centerLeft),
      const TextCell(itemContent: "950000", isAmount: true),
      const TextCell(itemContent: "920000", isAmount: true),
      const TextCell(itemContent: "24%"),
      const TextCell(itemContent: "112"),
      const TextCell(itemContent: "99.95%"),
    ],
    [
      const TextCell(
          itemContent: "Global Ops",
          textAlignment: Alignment.centerLeft,
          isBold: true),
      const TextCell(itemContent: "2150000", isAmount: true, isBold: true),
      const TextCell(itemContent: "2270000", isAmount: true, isBold: true),
      const TextCell(itemContent: "26%", isBold: true),
      const TextCell(itemContent: "257", isBold: true),
      const TextCell(itemContent: "99.97%", isBold: true),
    ],
  ];

  // ===========================================================================
  // EXAMPLE 2: EMPLOYEE REVIEW FORM (Interactive Grid)
  // ===========================================================================
  /// This grid demonstrates editable cells using `TextFieldCell`.
  final List<List<NrbHeaderCell>> _employeeHeaders = [
    [
      const NrbHeaderCell(
          text: "Employee",
          colSpan: 1,
          rowSpan: 2,
          backgroundColor: Color(0xFF1E88E5)),
      const NrbHeaderCell(
          text: "Core Metrics",
          colSpan: 2,
          backgroundColor: Color(0xFF1E88E5)),
      const NrbHeaderCell(
          text: "Manager Review",
          colSpan: 1,
          backgroundColor: Color(0xFF1E88E5)),
    ],
    [
      const NrbHeaderCell(
          text: "Tasks Completed", backgroundColor: Color(0xFF1E88E5)),
      const NrbHeaderCell(
          text: "Efficiency Score", backgroundColor: Color(0xFF1E88E5)),
      const NrbHeaderCell(
          text: "Bonus (Editable)", backgroundColor: Color(0xFF1E88E5)),
    ]
  ];

  final List<List<ReportCell>> _employeeData = [
    [
      const TextCell(
          itemContent: "Alice Smith", textAlignment: Alignment.centerLeft),
      const TextCell(itemContent: "124"),
      const TextCell(itemContent: "94%"),
      // Interactive Cell where users can type numbers directly into the table
      TextFieldCell(
          initialValue: "\$5,000", keyboardType: TextInputType.number),
    ],
    [
      const TextCell(
          itemContent: "Bob Jones", textAlignment: Alignment.centerLeft),
      const TextCell(itemContent: "98"),
      const TextCell(itemContent: "88%"),
      TextFieldCell(
          initialValue: "\$3,200", keyboardType: TextInputType.number),
    ],
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFFF5F7FA), // Light enterprise gray background
      appBar: AppBar(
        title: const Text(
          'NRB Enterprise Dashboard',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        backgroundColor: Colors.white,
        foregroundColor: Colors.black87,
        elevation: 1,
      ),
      body: LayoutBuilder(
        builder: (context, constraints) {
          final bool isDesktop = constraints.maxWidth > 1000;

          return SingleChildScrollView(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // -------------------------------------------------------------
                // SECTION 1: METRICS & KPI GAUGES
                // Demonstrating NRB Metric Cards, Donut Charts, and Gauges
                // -------------------------------------------------------------
                const _SectionTitle("Key Performance Indicators (NRB Charts)"),
                const SizedBox(height: 12),
                Wrap(
                  spacing: 16.0,
                  runSpacing: 16.0,
                  children: [
                    _buildKpiCard("Project Completion", 75.0, _primaryBrandColor),
                    _buildGaugeCard("Server Uptime", 99.9),
                    const NrbMetricCard(
                      title: "Daily Tasks",
                      value: "142",
                      backgroundColor: Color(0xFF1976D2),
                    ),
                  ],
                ),

                const SizedBox(height: 40),

                // -------------------------------------------------------------
                // SECTION 2: COMPLEX DATA GRIDS (NrbTableEngine)
                // This responsive layout places charts next to tables on desktop,
                // and stacks them vertically on mobile devices.
                // -------------------------------------------------------------
                if (isDesktop)
                  Row(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      // Left Column: Visual Analytics
                      Expanded(
                        flex: 4,
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            const _SectionTitle("Analytics (NRB Graphs)"),
                            const SizedBox(height: 12),
                            _buildChartCard(
                              title: "Monthly Revenue",
                              child: const NrbBarChart(
                                data: [120, 150, 180, 220, 300, 280],
                                labels: ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
                                height: 200,
                                width: double.infinity,
                                barColor: Color(0xFF0B7A3E),
                              ),
                            ),
                          ],
                        ),
                      ),
                      const SizedBox(width: 24),

                      // Right Column: Interactive Tables
                      Expanded(
                        flex: 6,
                        child: _buildDataGridColumn(),
                      ),
                    ],
                  )
                else
                // Mobile Layout: Stack everything vertically
                  Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const _SectionTitle("Analytics (NRB Graphs)"),
                      const SizedBox(height: 12),
                      _buildChartCard(
                        title: "Monthly Revenue",
                        child: const NrbBarChart(
                          data: [120, 150, 180, 220, 300, 280],
                          labels: ["Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
                          height: 150,
                          width: double.infinity,
                          barColor: Color(0xFF0B7A3E),
                        ),
                      ),
                      const SizedBox(height: 40),
                      _buildDataGridColumn(),
                    ],
                  ),

                const SizedBox(height: 40), // Bottom padding
              ],
            ),
          );
        },
      ),
    );
  }

  /// Builds the vertical column containing both NrbTableEngine examples.
  Widget _buildDataGridColumn() {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        // =====================================================================
        // NRB TABLE ENGINE EXAMPLE 1: The Exportable Grid
        // Features: Frozen first column, Excel/PDF exporting, custom branding.
        // =====================================================================
        const _SectionTitle("Regional Financials (NrbTableEngine - Exportable)"),
        const SizedBox(height: 12),
        _buildGridContainer(
          height: 380, // Constrain the height so it scrolls internally
          child: NrbTableEngine(
            frozenColumnsCount: 1, // Locks the 'Region' column during horizontal scroll
            headers: _financialHeaders,
            tableData: _financialData,
            primaryUiColor: _primaryBrandColor,
            primaryUiTextColor: Colors.white,

            // Enable the floating action button for downloading/sharing
            enableDownload: true,
            showDownloadFloatingButton: true,
            packageName: "com.inl.testapp", // Required for export backend
            apiKey: "fe2b22a6-fd19-4466-b2fa-ff7262a5993a", // Required for export backend
            reportName: "Financial_Report",
            onDownloadCompleted: _handleDownloadSuccess,
          ),
        ),

        const SizedBox(height: 40),

        // =====================================================================
        // NRB TABLE ENGINE EXAMPLE 2: The Interactive Form
        // Features: Text input fields directly inside the table structure.
        // =====================================================================
        const _SectionTitle("Employee Performance (NrbTableEngine - Editable)"),
        const SizedBox(height: 12),
        _buildGridContainer(
          height: 300,
          child: NrbTableEngine(
            frozenColumnsCount: 1,
            bodyCellHeight: 48, // Taller cells to comfortably fit TextFields
            headers: _employeeHeaders,
            tableData: _employeeData,
            primaryUiColor: _secondaryBrandColor,
            primaryUiTextColor: Colors.white,

            // Disable downloads for this specific editable grid
            enableDownload: false,
            showDownloadFloatingButton: false,
          ),
        ),
      ],
    );
  }

  // --- HELPER WIDGETS FOR UI STYLING ---

  /// A common container style for wrapping charts and tables in a clean card.
  Widget _buildGridContainer({required double height, required Widget child}) {
    return Container(
      height: height,
      width: double.infinity,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.05),
            blurRadius: 10,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      clipBehavior: Clip.antiAlias, // Ensures the table respects the border radius
      child: child,
    );
  }

  /// Builds a simple card wrapper around an NRB Chart widget.
  Widget _buildChartCard({required String title, required Widget child}) {
    return Container(
      width: double.infinity,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.05),
            blurRadius: 10,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        mainAxisSize: MainAxisSize.min,
        children: [
          Text(
            title,
            style: const TextStyle(
                fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black87),
          ),
          const SizedBox(height: 24),
          child,
        ],
      ),
    );
  }

  /// Builds a Donut KPI Chart.
  Widget _buildKpiCard(String title, double value, Color color) {
    return Container(
      width: 140,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.05),
            blurRadius: 10,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          NrbDonutChart(
            value: value,
            size: 70,
            progressColor: color,
            trackColor: Colors.grey.shade200,
            strokeWidth: 8,
            centerContent: Text(
              "${value.toStringAsFixed(1)}%",
              style: TextStyle(
                fontWeight: FontWeight.bold,
                fontSize: 14,
                color: Colors.grey.shade800,
              ),
            ),
          ),
          const SizedBox(height: 16),
          Text(
            title,
            textAlign: TextAlign.center,
            style: const TextStyle(
                fontSize: 12, fontWeight: FontWeight.w600, color: Colors.black54),
          ),
        ],
      ),
    );
  }

  /// Builds a Gauge KPI Chart.
  Widget _buildGaugeCard(String title, double percentage) {
    return Container(
      width: 140,
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(12),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.05),
            blurRadius: 10,
            offset: const Offset(0, 4),
          ),
        ],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          SizedBox(
            height: 70,
            child: Center(
              child: NrbGaugeChart(
                value: percentage,
                size: 100,
                strokeWidth: 12.0,
                showLabels: false,
                segments: [
                  NrbGaugeSegment(startValue: 0, endValue: 50, color: const Color(0xFFF0716A)),
                  NrbGaugeSegment(startValue: 50, endValue: 75, color: const Color(0xFFFFCA3A)),
                  NrbGaugeSegment(startValue: 75, endValue: 100, color: const Color(0xFF67B28C)),
                ],
                centerContent: Text(
                  "${percentage.toStringAsFixed(0)}%",
                  style: TextStyle(
                    fontWeight: FontWeight.bold,
                    fontSize: 14,
                    color: Colors.grey.shade800,
                  ),
                ),
              ),
            ),
          ),
          const SizedBox(height: 16),
          Text(
            title,
            textAlign: TextAlign.center,
            style: const TextStyle(
                fontSize: 12, fontWeight: FontWeight.w600, color: Colors.black54),
          ),
        ],
      ),
    );
  }

  // --- DEVICE NATIVE FILE DOWNLOADING ---
  /// Native handler for saving the exported document to the user's device.
  Future<void> _handleDownloadSuccess(Uint8List bytes, String fileName) async {
    if (!kIsWeb) {
      bool hasPermission = false;

      // Handle specific Android SDK permissions
      if (Platform.isAndroid) {
        final deviceInfo = DeviceInfoPlugin();
        final androidInfo = await deviceInfo.androidInfo;

        if (androidInfo.version.sdkInt >= 33) {
          hasPermission = true;
        } else {
          var status = await Permission.storage.status;
          if (!status.isGranted) {
            status = await Permission.storage.request();
          }
          hasPermission = status.isGranted;
        }
      } else {
        hasPermission = true; // iOS/Desktop
      }

      // Save file if permissions are granted
      if (hasPermission) {
        try {
          final directory = Directory('/storage/emulated/0/Download');
          if (!await directory.exists()) {
            await directory.create(recursive: true);
          }

          final file = File('${directory.path}/$fileName');
          await file.writeAsBytes(bytes);

          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                content: Text('Report saved to: ${file.path}'),
                backgroundColor: Colors.green,
                behavior: SnackBarBehavior.floating,
              ),
            );
          }
        } catch (e) {
          if (mounted) {
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(
                  content: Text('Save failed: $e'),
                  backgroundColor: Colors.red),
            );
          }
        }
      }
    }
  }
}

/// A simple helper for consistent section headings.
class _SectionTitle extends StatelessWidget {
  final String title;
  const _SectionTitle(this.title);

  @override
  Widget build(BuildContext context) {
    return Text(
      title,
      style: const TextStyle(
          fontSize: 18, fontWeight: FontWeight.bold, color: Colors.black87),
    );
  }
}
10
likes
110
points
483
downloads

Documentation

API reference

Publisher

verified publisherinnovatenestlabs.com

Weekly Downloads

A highly responsive Flutter table and report builder for complex nested headers, editable data grids, and premium Excel/PDF exports.

License

unknown (license)

Dependencies

cross_file, flutter, share_plus, web

More

Packages that depend on nrb