182 lines
6.6 KiB
Dart
182 lines
6.6 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:dartboard_resume/annotation_manager.dart';
|
|
import 'package:dartboard_resume/models/dartboard_data.dart';
|
|
import 'package:dartboard_resume/models/dartboard_misc.dart';
|
|
import 'package:dartboard_resume/models/experience.dart';
|
|
import 'package:dartboard_resume/models/theme.dart';
|
|
import 'package:dartboard_resume/widgets/dartboard_misc_entry.dart';
|
|
import 'package:dartboard_resume/widgets/experience_entry.dart';
|
|
import 'package:dartboard_resume/widgets/footer.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart';
|
|
import 'package:toml/toml.dart';
|
|
|
|
int? lastDartboardHash;
|
|
|
|
Future<void> renderPdf(String tomlFilePath, {bool force = false}) async {
|
|
try {
|
|
final start = DateTime.now().microsecondsSinceEpoch;
|
|
final dartboardData = DartboardData.fromToml(tomlFilePath);
|
|
if (lastDartboardHash == dartboardData.hashCode && !force) {
|
|
return;
|
|
}
|
|
lastDartboardHash = dartboardData.hashCode;
|
|
stdout.writeln("Detected change:\nRendering with new dartboard data: $lastDartboardHash");
|
|
final pdfFuture = Document()..addPage(_generatePdfPage(dartboardData: dartboardData, renderNs: 0));
|
|
await pdfFuture.save();
|
|
|
|
final renderNs = DateTime.now().microsecondsSinceEpoch - start;
|
|
|
|
final pdf = Document();
|
|
pdf.addPage(_generatePdfPage(dartboardData: dartboardData, renderNs: renderNs));
|
|
final file = File("example.pdf");
|
|
final bytes = await pdf.save();
|
|
|
|
stdout.writeln('New pdf file saved.');
|
|
file.writeAsBytesSync(bytes);
|
|
AnnotationManager().reset();
|
|
} catch (e, st) {
|
|
stderr.writeln('Encountered error: $e');
|
|
stderr.writeln(st);
|
|
try {
|
|
stderr.writeln('Current toml map:\n${TomlDocument.loadSync(tomlFilePath).toMap()}');
|
|
} catch (_) {
|
|
stderr.writeln('Cannot display current toml map');
|
|
}
|
|
}
|
|
}
|
|
|
|
Page _generatePdfPage({required DartboardData dartboardData, required int renderNs}) {
|
|
AnnotationManager().style = dartboardData.defaultTextStyle;
|
|
final List<Widget> groupedExperienceList = dartboardData.groupedExperiences.entries.map<Widget>(
|
|
(entry) {
|
|
final String subsection = entry.key;
|
|
final List<Experience> experiences = entry.value;
|
|
return Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Text(
|
|
subsection,
|
|
style: dartboardData.subheaderTextStyle
|
|
.merge(const TextStyle(fontSize: 18))
|
|
.apply(color: const PdfColorGrey(0.2)),
|
|
),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
Container(height: 2, width: 200, color: const PdfColorGrey(0.7)),
|
|
],
|
|
),
|
|
SizedBox(height: 3),
|
|
...experiences.map(
|
|
(Experience exp) => ExperienceEntry(dartboardData: dartboardData, exp: exp),
|
|
),
|
|
],
|
|
);
|
|
},
|
|
).toList();
|
|
final List<Widget> groupedMiscList = dartboardData.groupedMisc.entries.map<Widget>((entry) {
|
|
final String subsection = entry.key;
|
|
final List<DartboardMisc> miscs = entry.value;
|
|
return Column(
|
|
children: [
|
|
Row(
|
|
children: [
|
|
Text(
|
|
subsection,
|
|
style: dartboardData.subheaderTextStyle
|
|
.merge(const TextStyle(fontSize: 18))
|
|
.apply(color: const PdfColorGrey(0.2)),
|
|
),
|
|
],
|
|
),
|
|
Row(
|
|
children: [
|
|
Container(height: 2, width: 200, color: const PdfColorGrey(0.7)),
|
|
],
|
|
),
|
|
SizedBox(height: 3),
|
|
...miscs.map(
|
|
(DartboardMisc misc) => DartboardMiscEntry(dartboardData: dartboardData, misc: misc),
|
|
),
|
|
],
|
|
);
|
|
}).toList();
|
|
return Page(
|
|
pageTheme: PageTheme(
|
|
buildBackground: (_) => Container(color: dartboardData.backgroundColor),
|
|
pageFormat: PdfPageFormat.standard,
|
|
margin: EdgeInsets.zero,
|
|
),
|
|
build: (Context context) {
|
|
return FullPage(
|
|
ignoreMargins: true,
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(DocumentTheme.cm * 2),
|
|
child: Column(
|
|
children: [
|
|
if (dartboardData.imagePath == null)
|
|
Center(
|
|
child: Column(
|
|
children: [
|
|
Text(dartboardData.fullName, style: dartboardData.headerTextStyle),
|
|
if (dartboardData.phoneNumber != null)
|
|
Text(dartboardData.phoneNumber!, style: dartboardData.headerTextStyle),
|
|
if (dartboardData.email != null) Text(dartboardData.email!, style: dartboardData.headerTextStyle),
|
|
],
|
|
),
|
|
)
|
|
else
|
|
SizedBox(
|
|
height: 100,
|
|
width: double.infinity,
|
|
child: Stack(
|
|
children: [
|
|
if (dartboardData.imagePath != null)
|
|
Positioned(
|
|
left: 0,
|
|
child: Container(
|
|
height: 100,
|
|
width: 100,
|
|
decoration: BoxDecoration(
|
|
shape: BoxShape.circle,
|
|
image: DecorationImage(
|
|
fit: BoxFit.contain,
|
|
image: MemoryImage(
|
|
File(dartboardData.imagePath!).readAsBytesSync(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Center(
|
|
child: Column(
|
|
children: [
|
|
Text(dartboardData.fullName, style: dartboardData.headerTextStyle),
|
|
if (dartboardData.phoneNumber != null)
|
|
Text(dartboardData.phoneNumber!, style: dartboardData.headerTextStyle),
|
|
if (dartboardData.email != null)
|
|
Text(dartboardData.email!, style: dartboardData.headerTextStyle),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
...groupedExperienceList,
|
|
...groupedMiscList,
|
|
// this is quirky and gets evaluated before the actual footnotes get added up, so the original adding is done in the prerender
|
|
...AnnotationManager().footnotes,
|
|
DartboardFooter(dartboardData: dartboardData, renderNs: renderNs),
|
|
],
|
|
// ),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|