create static method

Uint8List create(
  1. Map<String, dynamic> workbook
)

Cria o arquivo XLSX compactado retornando os bytes.

Implementation

static Uint8List create(Map<String, dynamic> workbook) {
  const xmlHead = '<?xml version="1.0" encoding="UTF-8"?>';
  final zip = MinimalZip();

  // Relações básicas
  final types = [
    {
      'Extension': 'rels',
      'ContentType':
          'application/vnd.openxmlformats-package.relationships+xml'
    },
    {'Extension': 'xml', 'ContentType': 'application/xml'},
    {
      'PartName': '/xl/styles.xml',
      'ContentType':
          'application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml'
    },
    {
      'PartName': '/xl/workbook.xml',
      'ContentType':
          'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml'
    }
  ];

  final rels = [
    {
      'Id': 'rId0',
      'Type':
          'http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles',
      'Target': 'styles.xml'
    }
  ];

  final sheets = workbook['sheets'] as List<dynamic>;
  final sheetsXml = StringBuffer();

  // Estilos fixos mínimos
  const stylesXml =
      '''<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
    <numFmts count="2">
      <numFmt numFmtId="164" formatCode="yyyy-mm-dd"/>
      <numFmt numFmtId="165" formatCode="yyyy-mm-dd hh:mm:ss"/>
    </numFmts>
    <fonts count="2"><font><sz val="11"/><name val="Calibri"/></font><font><sz val="11"/><name val="Calibri"/><b/></font></fonts>
    <fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>
    <borders count="1"><border/></borders>
    <cellXfs count="4">
      <xf fontId="0" applyFont="1"/>
      <xf numFmtId="164" applyNumberFormat="1"/>
      <xf numFmtId="165" applyNumberFormat="1"/>
      <xf numFmtId="0" fontId="1" applyFont="1"/>
    </cellXfs>
  </styleSheet>''';

  for (int i = 0; i < sheets.length; i++) {
    final int sheetId = i + 1;
    final sheet = sheets[i] as Map<String, dynamic>;
    final String sheetName = sheet['name'] ?? 'Sheet$sheetId';
    final List<List<dynamic>> data =
        (sheet['data'] as List<dynamic>).cast<List<dynamic>>();

    final partName = '/xl/worksheets/sheet$sheetId.xml';
    types.add({
      'PartName': partName,
      'ContentType':
          'application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml'
    });
    rels.add({
      'Id': 'rId$sheetId',
      'Type':
          'http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet',
      'Target': 'worksheets/sheet$sheetId.xml'
    });

    sheetsXml.write(_toXml('sheet',
        {'name': sheetName, 'sheetId': sheetId, 'r:id': 'rId$sheetId'}));

    final sheetDataXml = StringBuffer();
    int rowIndex = 1;

    for (var row in data) {
      final rowXml = StringBuffer();
      for (int col = 0; col < row.length; col++) {
        final val = row[col];
        if (val == null) continue;

        final ref = '${_toCol(col)}$rowIndex';

        if (val is String) {
          rowXml.write(
              '<c r="$ref" t="inlineStr"><is><t>${_escape(val)}</t></is></c>');
        } else if (val is num) {
          rowXml.write('<c r="$ref"><v>$val</v></c>');
        } else if (val is bool) {
          rowXml.write('<c r="$ref" t="b"><v>${val ? 1 : 0}</v></c>');
        } else if (val is DateTime) {
          final double excelDate =
              val.difference(_excelEpoch).inMilliseconds / 86400000.0;
          // s="1" aponta para o formato de data yyyy-mm-dd
          rowXml.write(
              '<c r="$ref" s="1"><v>${excelDate.toStringAsFixed(6)}</v></c>');
        }
      }
      if (rowXml.isNotEmpty) {
        sheetDataXml.write('<row r="$rowIndex">$rowXml</row>');
      }
      rowIndex++;
    }

    final content = StringBuffer()
      ..write(xmlHead)
      ..write(
          '<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">')
      ..write('<sheetData>$sheetDataXml</sheetData>')
      ..write('</worksheet>');

    zip.addFile(
        'xl/worksheets/sheet$sheetId.xml', utf8.encode(content.toString()));
  }

  // [Content_Types].xml
  final typesXml = StringBuffer();
  for (var t in types) {
    if (t.containsKey('Extension')) {
      typesXml.write(_toXml('Default', t));
    } else {
      typesXml.write(_toXml('Override', t));
    }
  }
  zip.addFile(
      '[Content_Types].xml',
      utf8.encode(
          '$xmlHead<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">$typesXml</Types>'));

  // _rels/.rels
  zip.addFile(
      '_rels/.rels',
      utf8.encode(
          '$xmlHead<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>'));

  // xl/_rels/workbook.xml.rels
  final relsXml = StringBuffer();
  for (var r in rels) {
    relsXml.write(_toXml('Relationship', r));
  }
  zip.addFile(
      'xl/_rels/workbook.xml.rels',
      utf8.encode(
          '$xmlHead<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">$relsXml</Relationships>'));

  // xl/styles.xml
  zip.addFile('xl/styles.xml', utf8.encode(xmlHead + stylesXml));

  // xl/workbook.xml
  zip.addFile(
      'xl/workbook.xml',
      utf8.encode(
          '$xmlHead<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"><sheets>$sheetsXml</sheets></workbook>'));

  return zip.finish();
}