260 lines
8.1 KiB
Dart
260 lines
8.1 KiB
Dart
import 'package:dartboard_resume/dartboard_parser.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart';
|
|
|
|
class DartboardFooter extends StatelessWidget {
|
|
DartboardFooter({required this.dartboardData, required this.renderNs});
|
|
final int renderNs;
|
|
final DartboardData dartboardData;
|
|
|
|
@override
|
|
Widget build(Context context) {
|
|
final double renderTimeMs = renderNs.toDouble() / 1000.0;
|
|
return Padding(
|
|
padding: const EdgeInsets.only(top: 8.0),
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
|
children: [
|
|
Text(
|
|
'This resume was generated with DartBoard Resume',
|
|
style: dartboardData.defaultTextStyle.copyWith(fontSize: 10),
|
|
),
|
|
Text(
|
|
'Rendered in ${renderTimeMs.toStringAsFixed(2)}ms',
|
|
style: dartboardData.defaultTextStyle.copyWith(fontSize: 10),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class DartboardExperienceEntry extends StatelessWidget {
|
|
DartboardExperienceEntry({required this.dartboardData, required this.exp});
|
|
final DartboardData dartboardData;
|
|
final DartboardExperience exp;
|
|
|
|
@override
|
|
Widget build(Context context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(left: 4.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(exp.title, style: dartboardData.subheaderTextStyle.apply(color: const PdfColorGrey(0.3))),
|
|
Container(height: 1, width: 60, color: const PdfColorGrey(0.75)),
|
|
],
|
|
),
|
|
),
|
|
Column(
|
|
crossAxisAlignment: CrossAxisAlignment.end,
|
|
children: [
|
|
Text(
|
|
exp.range.toString(),
|
|
style: dartboardData.defaultTextStyle.copyWith(color: const PdfColorGrey(0.42), fontSize: 8.0),
|
|
),
|
|
if (exp.location != null)
|
|
Text(
|
|
exp.location!,
|
|
style: dartboardData.defaultTextStyle.copyWith(color: const PdfColorGrey(0.42), fontSize: 8.0),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
SizedBox(height: 6),
|
|
...exp.attributes.map(
|
|
(a) => Padding(
|
|
child: DartboardTextWithLink(
|
|
stringSections: a.toTextLinkList(),
|
|
bulletString: dartboardData.dartboardTheme.bulletPoint,
|
|
style: dartboardData.defaultTextStyle.apply(
|
|
color: const PdfColorGrey(0.55),
|
|
),
|
|
),
|
|
padding: const EdgeInsets.only(left: 8.0, bottom: 4.0),
|
|
),
|
|
),
|
|
SizedBox(height: 12),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class DartboardMiscEntry extends StatelessWidget {
|
|
DartboardMiscEntry({required this.dartboardData, required this.misc});
|
|
final DartboardData dartboardData;
|
|
final DartboardMisc misc;
|
|
|
|
@override
|
|
Widget build(Context context) {
|
|
return Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
...misc.attributes.map(
|
|
(a) => Padding(
|
|
padding: const EdgeInsets.only(left: 8.0, bottom: 4.0),
|
|
child: DartboardTextWithLink(
|
|
stringSections: a.toTextLinkList(),
|
|
bulletString: dartboardData.dartboardTheme.bulletPoint,
|
|
style: dartboardData.defaultTextStyle.apply(
|
|
color: const PdfColorGrey(0.55),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SizedBox(height: 12),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class UrlFootnotes {
|
|
// Factory constructor to return the single instance
|
|
factory UrlFootnotes() {
|
|
return _instance;
|
|
}
|
|
|
|
// Private constructor
|
|
UrlFootnotes._privateConstructor();
|
|
|
|
// Static field to hold the single instance of the class
|
|
static final UrlFootnotes _instance = UrlFootnotes._privateConstructor();
|
|
|
|
// Field to hold the number
|
|
int _numUrls = 0;
|
|
List<Widget> _urlWidgets = [];
|
|
TextStyle? _style;
|
|
|
|
// ignore: avoid_setters_without_getters
|
|
set style(TextStyle style) => _style = style;
|
|
|
|
int add({required String url}) {
|
|
_numUrls += 1;
|
|
if (_style == null) {
|
|
throw Exception('Must provide text style for urls');
|
|
}
|
|
_urlWidgets.add(Footnote(number: _numUrls, style: _style!, url: url));
|
|
print(_urlWidgets);
|
|
return _numUrls;
|
|
}
|
|
|
|
List<Widget> get footnotes {
|
|
final widgets = [..._urlWidgets];
|
|
reset();
|
|
return widgets;
|
|
}
|
|
|
|
// Method to reset the number
|
|
void reset() {
|
|
_numUrls = 0;
|
|
_urlWidgets = [];
|
|
}
|
|
}
|
|
|
|
// TODO this lays out long text lines on a newline after a uilink rather than soft wrapping it.
|
|
class DartboardTextWithLink extends StatelessWidget {
|
|
DartboardTextWithLink({this.bulletString, required this.stringSections, this.style});
|
|
|
|
final String? bulletString;
|
|
final List<DartboardTextLinkData> stringSections;
|
|
final TextStyle? style;
|
|
|
|
@override
|
|
Widget build(Context context) {
|
|
return Row(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(bulletString == null ? '' : '$bulletString ', style: style),
|
|
SizedBox(
|
|
width: DartboardTheme.width - DartboardTheme.margin * 2 - 20.0,
|
|
child: RichText(
|
|
text: TextSpan(
|
|
children: [
|
|
...stringSections.map((s) {
|
|
return TextSpan(text: s.text, style: style);
|
|
// switch (s.type) {
|
|
// case DartboardTextType.normal:
|
|
// return [Text(s.text, style: style)];
|
|
// case DartboardTextType.linkText:
|
|
// final number = UrlFootnotes().add(url: s.url!);
|
|
// return [
|
|
// Text(s.text, style: style),
|
|
// UrlLink(
|
|
// destination: s.url!,
|
|
// child: Padding(
|
|
// padding: const EdgeInsets.only(bottom: 4.0, left: 2.0, right: 2.0),
|
|
// child: Text(
|
|
// number.toString(),
|
|
// style: style?.copyWith(color: PdfColors.blue, fontSize: 8),
|
|
// ),
|
|
// ),
|
|
// ),
|
|
// ];
|
|
// }
|
|
}),
|
|
...stringSections.map((s) {
|
|
switch (s.type) {
|
|
case DartboardTextType.normal:
|
|
return null;
|
|
case DartboardTextType.linkText:
|
|
final number = UrlFootnotes().add(url: s.url!);
|
|
return TextSpan(
|
|
text: ' [$number]',
|
|
style: style?.copyWith(color: PdfColors.blue, fontSize: 8),
|
|
);
|
|
// return UrlLink(
|
|
// destination: s.url!,
|
|
// child: Padding(
|
|
// padding: const EdgeInsets.only(bottom: 4.0, left: 2.0, right: 2.0),
|
|
// child: Text(
|
|
// number.toString(),
|
|
// style: style?.copyWith(color: PdfColors.blue, fontSize: 8),
|
|
// ),
|
|
// ),
|
|
// );
|
|
}
|
|
}).nonNulls,
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|
|
|
|
class Footnote extends StatelessWidget {
|
|
Footnote({required this.number, required this.url, required this.style});
|
|
|
|
final String url;
|
|
final int number;
|
|
final TextStyle style;
|
|
|
|
@override
|
|
Widget build(Context context) {
|
|
return Row(
|
|
children: [
|
|
UrlLink(
|
|
destination: url,
|
|
child: Text(
|
|
'[$number]',
|
|
style: style.copyWith(color: PdfColors.blue, fontSize: 8),
|
|
),
|
|
),
|
|
Text(
|
|
' $url',
|
|
style: style.copyWith(fontSize: 8),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|