282 lines
8.4 KiB
Dart
282 lines
8.4 KiB
Dart
import 'dart:io';
|
|
|
|
import 'package:intl/intl.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart';
|
|
import 'package:toml/toml.dart';
|
|
|
|
class DartboardData {
|
|
DartboardData({
|
|
required this.fullName,
|
|
required this.phoneNumber,
|
|
required this.email,
|
|
// required this.address,
|
|
required this.imagePath,
|
|
required this.dartboardTheme,
|
|
required this.experiences,
|
|
required this.miscList,
|
|
});
|
|
|
|
factory DartboardData.fromToml(String tomlFilePath) {
|
|
final tomlData = TomlDocument.loadSync(tomlFilePath).toMap();
|
|
|
|
final List<DartboardExperience> exps = tomlData.entries
|
|
.where((e) => e.value is List && (e.value as List).firstOrNull is Map)
|
|
.map((MapEntry<String, dynamic> expsEntry) {
|
|
final String subsection = tomlData['${expsEntry.key}_name'] as String? ?? '';
|
|
final exps = (expsEntry.value as List).map((e) => e as Map<String, dynamic>).toList();
|
|
return exps.map((exp) {
|
|
final TomlLocalDate? start = exp['start'] as TomlLocalDate?;
|
|
final TomlLocalDate? end = exp['end'] as TomlLocalDate?;
|
|
return DartboardExperience(
|
|
title: exp['title'] as String,
|
|
subsection: subsection,
|
|
range: DateRange(
|
|
start: start == null ? null : DateTime(start.date.year, start.date.month),
|
|
end: end == null ? null : DateTime(end.date.year, end.date.month),
|
|
),
|
|
attributes: (exp['attributes'] as List).map((e) => DartboardText(content: e as String)).toList(),
|
|
location: exp['location'] as String?,
|
|
);
|
|
}).toList();
|
|
})
|
|
.expand((i) => i)
|
|
.toList();
|
|
return DartboardData(
|
|
fullName: tomlData['full_name'] as String,
|
|
phoneNumber: tomlData['phone_number'] as String,
|
|
email: tomlData['email'] as String,
|
|
imagePath: tomlData['image'] as String,
|
|
dartboardTheme: DartboardTheme.fromToml(tomlData),
|
|
experiences: exps,
|
|
miscList: [
|
|
DartboardList(subsection: 'Skills & Interest', content: 'Proficient in flutter and other'),
|
|
],
|
|
);
|
|
}
|
|
|
|
final String fullName;
|
|
final String phoneNumber;
|
|
final String email;
|
|
// final String address;
|
|
final String imagePath;
|
|
final DartboardTheme dartboardTheme;
|
|
final List<DartboardExperience> experiences;
|
|
final List<DartboardList> miscList;
|
|
|
|
Font get font => dartboardTheme.font;
|
|
|
|
PdfColor get primaryColor => dartboardTheme.primaryColor;
|
|
PdfColor get accentColor => dartboardTheme.accentColor;
|
|
PdfColor get backgroundColor => dartboardTheme.backgroundColor;
|
|
|
|
TextStyle get headerTextStyle =>
|
|
TextStyle(fontSize: 18, font: font, fontWeight: FontWeight.bold, color: const PdfColorGrey(0.18));
|
|
TextStyle get subheaderTextStyle => TextStyle(fontSize: 14, font: font, color: const PdfColorGrey(0.3));
|
|
TextStyle get defaultTextStyle => TextStyle(fontSize: 10, font: font, color: const PdfColorGrey(0.45));
|
|
|
|
Map<String, List<DartboardExperience>> get groupedExperiences {
|
|
final Map<String, List<DartboardExperience>> exps = {};
|
|
for (final DartboardExperience exp in experiences) {
|
|
if (!exps.containsKey(exp.subsection)) {
|
|
exps[exp.subsection] = <DartboardExperience>[];
|
|
}
|
|
exps[exp.subsection]!.add(exp);
|
|
}
|
|
return exps;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([fullName, phoneNumber, email, imagePath, ...experiences]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
class DartboardExperience {
|
|
DartboardExperience({
|
|
required this.title,
|
|
required this.attributes,
|
|
required this.range,
|
|
required this.subsection,
|
|
this.location,
|
|
});
|
|
final String subsection;
|
|
final String title;
|
|
String? location;
|
|
final List<DartboardText> attributes;
|
|
final DateRange range;
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([subsection, title, ...attributes, range]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
class DateRange {
|
|
DateRange({required this.start, required this.end});
|
|
final DateTime? start;
|
|
final DateTime? end;
|
|
|
|
@override
|
|
String toString() {
|
|
final DateFormat dateFormat = DateFormat("MMM yyyy");
|
|
if (start == null && end == null) {
|
|
return '';
|
|
}
|
|
if (start == null && end != null) {
|
|
return dateFormat.format(end!);
|
|
}
|
|
if (start != null && end == null) {
|
|
return "${dateFormat.format(start!)} - Current";
|
|
}
|
|
return "${dateFormat.format(start!)} - ${dateFormat.format(end!)}";
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([start, end]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
class DartboardList {
|
|
DartboardList({required this.subsection, required this.content});
|
|
final String subsection;
|
|
final String content;
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([subsection, content]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
class DartboardTheme {
|
|
DartboardTheme({
|
|
required this.primaryHex,
|
|
required this.accentHex,
|
|
required this.backgroundHex,
|
|
required this.fontPath,
|
|
required this.bulletPoint,
|
|
});
|
|
|
|
factory DartboardTheme.fromToml(Map<String, dynamic> toml) => DartboardTheme(
|
|
primaryHex: (toml['theme'] as Map)['primary_hex'] as String,
|
|
accentHex: (toml['theme'] as Map)['accent_hex'] as String,
|
|
backgroundHex: (toml['theme'] as Map)['background_hex'] as String,
|
|
fontPath: (toml['theme'] as Map)['font'] as String,
|
|
bulletPoint: (toml['theme'] as Map)['bullet_point'] as String? ?? '-',
|
|
);
|
|
|
|
factory DartboardTheme.retro() => DartboardTheme(
|
|
primaryHex: "00AA00",
|
|
accentHex: "44EE66",
|
|
backgroundHex: "FFFFFF",
|
|
fontPath: "nerd.ttf",
|
|
bulletPoint: '-',
|
|
);
|
|
|
|
static const double inch = 72.0;
|
|
static const double cm = inch / 2.54;
|
|
static const double mm = inch / 25.4;
|
|
|
|
static const width = 21.0 * cm;
|
|
static const height = 29.7 * cm;
|
|
static const margin = 2.0 * cm;
|
|
|
|
final String primaryHex;
|
|
final String accentHex;
|
|
final String backgroundHex;
|
|
final String fontPath;
|
|
final String bulletPoint;
|
|
Font? _font;
|
|
|
|
PdfColor get primaryColor => PdfColor.fromHex(primaryHex);
|
|
PdfColor get accentColor => PdfColor.fromHex(accentHex);
|
|
PdfColor get backgroundColor => PdfColor.fromHex(backgroundHex);
|
|
|
|
Font get font {
|
|
_font ??= Font.ttf(File(fontPath).readAsBytesSync().buffer.asByteData());
|
|
return _font!;
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([primaryHex, accentHex, backgroundHex, fontPath, bulletPoint]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
enum DartboardTextType { normal, linkText }
|
|
|
|
typedef DartboardTextLinkData = ({String text, String? url, DartboardTextType type});
|
|
|
|
/// Automatically detects and parses strings with hypertext in a markdown format
|
|
class DartboardText {
|
|
DartboardText({required this.content});
|
|
|
|
final String content;
|
|
static final _markdownLinkRegex = RegExp(r'\[(.*?)\]\((.*?)\)');
|
|
|
|
bool get hasLinkMarkup => _markdownLinkRegex.hasMatch(content);
|
|
|
|
List<DartboardTextLinkData> toTextLinkList() {
|
|
final markdownLinkRegex = RegExp(r'\[(.*?)\]\((.*?)\)');
|
|
if (markdownLinkRegex.hasMatch(content)) {
|
|
final matches = markdownLinkRegex.allMatches(content).toList();
|
|
final List<DartboardTextLinkData> stringSections = [];
|
|
int prevStartIndex = 0;
|
|
while (matches.isNotEmpty) {
|
|
final match = matches.removeAt(0);
|
|
stringSections
|
|
.add((text: content.substring(prevStartIndex, match.start), url: null, type: DartboardTextType.normal));
|
|
stringSections.add((text: match.group(1)!, url: match.group(2), type: DartboardTextType.linkText));
|
|
prevStartIndex = match.end;
|
|
}
|
|
stringSections
|
|
.add((text: content.substring(prevStartIndex, content.length), url: null, type: DartboardTextType.normal));
|
|
return stringSections;
|
|
} else {
|
|
return [(text: content, url: null, type: DartboardTextType.normal)];
|
|
// return Text("${bulletString != null ? '$bulletString ' : ''}$content", style: style);
|
|
}
|
|
}
|
|
|
|
@override
|
|
int get hashCode {
|
|
return Object.hashAll([content]);
|
|
}
|
|
|
|
@override
|
|
bool operator ==(Object other) {
|
|
return super.hashCode == other.hashCode;
|
|
}
|
|
}
|
|
|
|
String _getSubsectionFromKey(String key) {
|
|
switch (key) {
|
|
case 'exp':
|
|
}
|
|
}
|