nrb 4.0.5
nrb: ^4.0.5 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:typed_data';
import 'package:flutter/material.dart';
// Ensure your package is correctly imported
import 'package:nrb/nrb.dart';
import 'export_file_saver.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 {
await saveExportedReport(context, bytes, fileName);
}
}
/// 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,
),
);
}
}