WIP hot reloading enabled, much progress
This commit is contained in:
commit
976c3d0679
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# https://dart.dev/guides/libraries/private-files
|
||||||
|
# Created by `dart pub`
|
||||||
|
.dart_tool/
|
||||||
|
.direnv/**
|
||||||
|
|
||||||
|
*.toml
|
||||||
|
*.pdf
|
||||||
|
*.jpeg
|
||||||
|
*.png
|
||||||
|
*.JPEG
|
3
CHANGELOG.md
Normal file
3
CHANGELOG.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
## 1.0.0
|
||||||
|
|
||||||
|
- Initial version.
|
2
README.md
Normal file
2
README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
A sample command-line application with an entrypoint in `bin/`, library code
|
||||||
|
in `lib/`, and example unit test in `test/`.
|
12
analysis_options.yaml
Normal file
12
analysis_options.yaml
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
include: package:lint/strict.yaml
|
||||||
|
|
||||||
|
# linter:
|
||||||
|
# rules:
|
||||||
|
# - camel_case_types
|
||||||
|
analyzer:
|
||||||
|
language:
|
||||||
|
strict-casts: true
|
||||||
|
strict-inference: true
|
||||||
|
strict-raw-types: true
|
||||||
|
exclude:
|
||||||
|
# - path/to/excluded/files/**
|
47
bin/dartboard_resume.dart
Normal file
47
bin/dartboard_resume.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dartboard_resume/render.dart';
|
||||||
|
import 'package:hotreloader/hotreloader.dart';
|
||||||
|
import 'package:logging/logging.dart' as logging;
|
||||||
|
|
||||||
|
StreamSubscription<FileSystemEvent>? fileStreamSub;
|
||||||
|
StreamSubscription<String>? stdinStreamSub;
|
||||||
|
|
||||||
|
Future<void> main(List<String> arguments) async {
|
||||||
|
const String tomlFilePath = "resume.toml";
|
||||||
|
logging.hierarchicalLoggingEnabled = true;
|
||||||
|
HotReloader.logLevel = logging.Level.INFO;
|
||||||
|
final HotReloader reloader = await HotReloader.create();
|
||||||
|
|
||||||
|
stdin.lineMode = false;
|
||||||
|
stdin.echoMode = false;
|
||||||
|
stdin.echoNewlineMode = false;
|
||||||
|
stdinStreamSub = stdin.transform(const Utf8Decoder()).transform(const LineSplitter()).listen(
|
||||||
|
(event) {
|
||||||
|
if (event == "r") {
|
||||||
|
stdout.writeln("Triggering pdf render...");
|
||||||
|
renderPdf(tomlFilePath, force: true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
ProcessSignal.sigint.watch().listen((_) {
|
||||||
|
stdout.writeln('SIGINT received. Exiting gracefully...');
|
||||||
|
fileStreamSub?.cancel();
|
||||||
|
stdinStreamSub?.cancel();
|
||||||
|
// Perform cleanup or other necessary actions here
|
||||||
|
reloader.stop();
|
||||||
|
exit(0); // Exit with code 0 to indicate a successful termination
|
||||||
|
});
|
||||||
|
if (FileSystemEntity.isWatchSupported) {
|
||||||
|
final fileStream = File(tomlFilePath).watch(events: FileSystemEvent.modify);
|
||||||
|
fileStreamSub = fileStream.listen((e) {
|
||||||
|
renderPdf(tomlFilePath);
|
||||||
|
});
|
||||||
|
stdout.writeln('Watching for file changes.');
|
||||||
|
} else {
|
||||||
|
renderPdf(tomlFilePath);
|
||||||
|
}
|
||||||
|
}
|
61
flake.lock
Normal file
61
flake.lock
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1710146030,
|
||||||
|
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1719848872,
|
||||||
|
"narHash": "sha256-H3+EC5cYuq+gQW8y0lSrrDZfH71LB4DAf+TDFyvwCNA=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "00d80d13810dbfea8ab4ed1009b09100cca86ba8",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
25
flake.nix
Normal file
25
flake.nix
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
{
|
||||||
|
description = "Simple dart flake";
|
||||||
|
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
inputs.flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
|
||||||
|
outputs = {
|
||||||
|
flake-utils,
|
||||||
|
nixpkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system: let
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system;
|
||||||
|
};
|
||||||
|
in {
|
||||||
|
devShell = pkgs.mkShell {
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
dart
|
||||||
|
];
|
||||||
|
# shellHook = ''
|
||||||
|
# export FLUTTER_ROOT
|
||||||
|
# '';
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
281
lib/dartboard_parser.dart
Normal file
281
lib/dartboard_parser.dart
Normal file
|
@ -0,0 +1,281 @@
|
||||||
|
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':
|
||||||
|
}
|
||||||
|
}
|
101
lib/dartboard_resume.dart
Normal file
101
lib/dartboard_resume.dart
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dartboard_resume/dartboard_parser.dart';
|
||||||
|
import 'package:dartboard_resume/dartboard_widgets.dart';
|
||||||
|
import 'package:pdf/pdf.dart';
|
||||||
|
import 'package:pdf/widgets.dart';
|
||||||
|
|
||||||
|
Page generatePdfPage({required DartboardData dartboardData, required int renderNs}) {
|
||||||
|
final List<Widget> groupedExperienceList = dartboardData.groupedExperiences.entries.map<Widget>(
|
||||||
|
(entry) {
|
||||||
|
final String subsection = entry.key;
|
||||||
|
final List<DartboardExperience> experiences = entry.value;
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
subsection,
|
||||||
|
style: dartboardData.subheaderTextStyle
|
||||||
|
.merge(const TextStyle(fontSize: 18))
|
||||||
|
.apply(color: const PdfColorGrey(0.2)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(height: 2, width: 200, color: const PdfColorGrey(0.7)),
|
||||||
|
...experiences.map(
|
||||||
|
(DartboardExperience exp) => Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(exp.title, style: dartboardData.subheaderTextStyle.apply(color: const PdfColorGrey(0.3))),
|
||||||
|
Text(
|
||||||
|
exp.range.toString(),
|
||||||
|
style: dartboardData.subheaderTextStyle.apply(color: const PdfColorGrey(0.42)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
...exp.attributes.map(
|
||||||
|
(a) => Text(
|
||||||
|
"${dartboardData.dartboardTheme.bulletPoint} $a",
|
||||||
|
style: dartboardData.defaultTextStyle.apply(
|
||||||
|
color: const PdfColorGrey(0.55),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DartboardFooter(dartboardData: dartboardData, renderNs: renderNs),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return Page(
|
||||||
|
pageTheme: const PageTheme(pageFormat: PdfPageFormat.standard),
|
||||||
|
build: (Context context) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 120,
|
||||||
|
width: double.infinity,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
|
Text(dartboardData.phoneNumber, style: dartboardData.headerTextStyle),
|
||||||
|
Text(dartboardData.email, style: dartboardData.headerTextStyle),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(height: 20),
|
||||||
|
...groupedExperienceList,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
123
lib/dartboard_widgets.dart
Normal file
123
lib/dartboard_widgets.dart
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
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 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: [
|
||||||
|
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.apply(color: const PdfColorGrey(0.42)),
|
||||||
|
),
|
||||||
|
if (exp.location != null)
|
||||||
|
Text(
|
||||||
|
exp.location!,
|
||||||
|
style: dartboardData.defaultTextStyle.apply(color: const PdfColorGrey(0.42)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
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(bottom: 4.0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 20),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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: Wrap(
|
||||||
|
children: [
|
||||||
|
...stringSections.map((s) {
|
||||||
|
switch (s.type) {
|
||||||
|
case DartboardTextType.normal:
|
||||||
|
return Text(s.text, style: style);
|
||||||
|
case DartboardTextType.linkText:
|
||||||
|
return UrlLink(
|
||||||
|
destination: s.url!,
|
||||||
|
child: Text(
|
||||||
|
s.text,
|
||||||
|
style: style?.copyWith(color: PdfColors.blue),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
118
lib/render.dart
Normal file
118
lib/render.dart
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:dartboard_resume/dartboard_parser.dart';
|
||||||
|
import 'package:dartboard_resume/dartboard_widgets.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);
|
||||||
|
stdout.writeln('Reloading llpp...');
|
||||||
|
Process.runSync('pkill', ['-HUP', 'llpp']);
|
||||||
|
} catch (e) {
|
||||||
|
stderr.writeln('Encountered error: $e');
|
||||||
|
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}) {
|
||||||
|
final List<Widget> groupedExperienceList = dartboardData.groupedExperiences.entries.map<Widget>(
|
||||||
|
(entry) {
|
||||||
|
final String subsection = entry.key;
|
||||||
|
final List<DartboardExperience> experiences = entry.value;
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
subsection,
|
||||||
|
style: dartboardData.subheaderTextStyle
|
||||||
|
.merge(const TextStyle(fontSize: 18))
|
||||||
|
.apply(color: const PdfColorGrey(0.2)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Container(height: 2, width: 200, color: const PdfColorGrey(0.7)),
|
||||||
|
...experiences.map(
|
||||||
|
(DartboardExperience exp) => DartboardExperienceEntry(dartboardData: dartboardData, exp: exp),
|
||||||
|
),
|
||||||
|
DartboardFooter(dartboardData: dartboardData, renderNs: renderNs),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
).toList();
|
||||||
|
return Page(
|
||||||
|
pageTheme: const PageTheme(pageFormat: PdfPageFormat.standard),
|
||||||
|
build: (Context context) {
|
||||||
|
return
|
||||||
|
// FullPage(
|
||||||
|
// ignoreMargins: true,
|
||||||
|
// child:
|
||||||
|
Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 120,
|
||||||
|
width: double.infinity,
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
|
Text(dartboardData.phoneNumber, style: dartboardData.headerTextStyle),
|
||||||
|
Text(dartboardData.email, style: dartboardData.headerTextStyle),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(height: 20),
|
||||||
|
...groupedExperienceList,
|
||||||
|
],
|
||||||
|
// ),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
5
lib/utils.dart
Normal file
5
lib/utils.dart
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
extension StringUtils on String {
|
||||||
|
String capitalize() {
|
||||||
|
return substring(0, 1).toUpperCase() + substring(1);
|
||||||
|
}
|
||||||
|
}
|
530
pubspec.lock
Normal file
530
pubspec.lock
Normal file
|
@ -0,0 +1,530 @@
|
||||||
|
# Generated by pub
|
||||||
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
|
packages:
|
||||||
|
_fe_analyzer_shared:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: _fe_analyzer_shared
|
||||||
|
sha256: "5aaf60d96c4cd00fe7f21594b5ad6a1b699c80a27420f8a837f4d68473ef09e3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "68.0.0"
|
||||||
|
_macros:
|
||||||
|
dependency: transitive
|
||||||
|
description: dart
|
||||||
|
source: sdk
|
||||||
|
version: "0.1.0"
|
||||||
|
analyzer:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: analyzer
|
||||||
|
sha256: "21f1d3720fd1c70316399d5e2bccaebb415c434592d778cce8acb967b8578808"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
|
archive:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: archive
|
||||||
|
sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.6.1"
|
||||||
|
args:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: args
|
||||||
|
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.0"
|
||||||
|
async:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: async
|
||||||
|
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.0"
|
||||||
|
barcode:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: barcode
|
||||||
|
sha256: ab180ce22c6555d77d45f0178a523669db67f95856e3378259ef2ffeb43e6003
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.2.8"
|
||||||
|
bidi:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: bidi
|
||||||
|
sha256: "9a712c7ddf708f7c41b1923aa83648a3ed44cfd75b04f72d598c45e5be287f9d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.12"
|
||||||
|
boolean_selector:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: boolean_selector
|
||||||
|
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
|
clock:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: clock
|
||||||
|
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.1"
|
||||||
|
collection:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: collection
|
||||||
|
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.19.0"
|
||||||
|
convert:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: convert
|
||||||
|
sha256: "0f08b14755d163f6e2134cb58222dd25ea2a2ee8a195e53983d57c075324d592"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.1"
|
||||||
|
coverage:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: coverage
|
||||||
|
sha256: c1fb2dce3c0085f39dc72668e85f8e0210ec7de05345821ff58530567df345a5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.2"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
sha256: ec30d999af904f33454ba22ed9a86162b35e52b44ac4807d1d93c288041d7d27
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.5"
|
||||||
|
file:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: file
|
||||||
|
sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.0.0"
|
||||||
|
frontend_server_client:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: frontend_server_client
|
||||||
|
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.0.0"
|
||||||
|
glob:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: glob
|
||||||
|
sha256: "0e7014b3b7d4dac1ca4d6114f82bf1782ee86745b9b42a92c9289c23d8a0ab63"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
hotreloader:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: hotreloader
|
||||||
|
sha256: ed56fdc1f3a8ac924e717257621d09e9ec20e308ab6352a73a50a1d7a4d9158e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.0"
|
||||||
|
http_multi_server:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_multi_server
|
||||||
|
sha256: "97486f20f9c2f7be8f514851703d0119c3596d14ea63227af6f7a481ef2b2f8b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.2.1"
|
||||||
|
http_parser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: http_parser
|
||||||
|
sha256: "40f592dd352890c3b60fec1b68e786cefb9603e05ff303dbc4dda49b304ecdf4"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
|
image:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: image
|
||||||
|
sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.2.0"
|
||||||
|
intl:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: intl
|
||||||
|
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.19.0"
|
||||||
|
io:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: io
|
||||||
|
sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.4"
|
||||||
|
js:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: js
|
||||||
|
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.1"
|
||||||
|
lint:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: lint
|
||||||
|
sha256: d758a5211fce7fd3f5e316f804daefecdc34c7e53559716125e6da7388ae8565
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.0"
|
||||||
|
lints:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: lints
|
||||||
|
sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
|
logging:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: logging
|
||||||
|
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.0"
|
||||||
|
macros:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: macros
|
||||||
|
sha256: "12e8a9842b5a7390de7a781ec63d793527582398d16ea26c60fed58833c9ae79"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.0-main.0"
|
||||||
|
matcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: matcher
|
||||||
|
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.12.16+1"
|
||||||
|
meta:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: meta
|
||||||
|
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.15.0"
|
||||||
|
mime:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: mime
|
||||||
|
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
|
node_preamble:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: node_preamble
|
||||||
|
sha256: "6e7eac89047ab8a8d26cf16127b5ed26de65209847630400f9aefd7cd5c730db"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
|
package_config:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: package_config
|
||||||
|
sha256: "1c5b77ccc91e4823a5af61ee74e6b972db1ef98c2ff5a18d3161c982a55448bd"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
path:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path
|
||||||
|
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.9.0"
|
||||||
|
path_parsing:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: path_parsing
|
||||||
|
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
|
pdf:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: pdf
|
||||||
|
sha256: "05df53f8791587402493ac97b9869d3824eccbc77d97855f4545cf72df3cae07"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.11.1"
|
||||||
|
petitparser:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: petitparser
|
||||||
|
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.0.2"
|
||||||
|
pool:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pool
|
||||||
|
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.5.1"
|
||||||
|
pub_semver:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: pub_semver
|
||||||
|
sha256: "40d3ab1bbd474c4c2328c91e3a7df8c6dd629b79ece4c4bd04bee496a224fb0c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
shelf:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf
|
||||||
|
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.4.2"
|
||||||
|
shelf_packages_handler:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_packages_handler
|
||||||
|
sha256: "89f967eca29607c933ba9571d838be31d67f53f6e4ee15147d5dc2934fee1b1e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
|
shelf_static:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_static
|
||||||
|
sha256: a41d3f53c4adf0f57480578c1d61d90342cd617de7fc8077b1304643c2d85c1e
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
|
shelf_web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: shelf_web_socket
|
||||||
|
sha256: "073c147238594ecd0d193f3456a5fe91c4b0abbcc68bf5cd95b36c4e194ac611"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
|
source_map_stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_map_stack_trace
|
||||||
|
sha256: c0713a43e323c3302c2abe2a1cc89aa057a387101ebd280371d6a6c9fa68516b
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
source_maps:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_maps
|
||||||
|
sha256: "708b3f6b97248e5781f493b765c3337db11c5d2c81c3094f10904bfa8004c703"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.12"
|
||||||
|
source_span:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: source_span
|
||||||
|
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.10.0"
|
||||||
|
stack_trace:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stack_trace
|
||||||
|
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.11.1"
|
||||||
|
stream_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_channel
|
||||||
|
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.2"
|
||||||
|
stream_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: stream_transform
|
||||||
|
sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.0"
|
||||||
|
string_scanner:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: string_scanner
|
||||||
|
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
|
term_glyph:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: term_glyph
|
||||||
|
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
test:
|
||||||
|
dependency: "direct dev"
|
||||||
|
description:
|
||||||
|
name: test
|
||||||
|
sha256: "713a8789d62f3233c46b4a90b174737b2c04cb6ae4500f2aa8b1be8f03f5e67f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.25.8"
|
||||||
|
test_api:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_api
|
||||||
|
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.7.3"
|
||||||
|
test_core:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: test_core
|
||||||
|
sha256: "12391302411737c176b0b5d6491f466b0dd56d4763e347b6714efbaa74d7953d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.6.5"
|
||||||
|
toml:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: toml
|
||||||
|
sha256: d968d149c8bd06dc14e09ea3a140f90a3f2ba71949e7a91df4a46f3107400e71
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.16.0"
|
||||||
|
typed_data:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: typed_data
|
||||||
|
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.2"
|
||||||
|
vector_math:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vector_math
|
||||||
|
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.4"
|
||||||
|
vm_service:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vm_service
|
||||||
|
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "14.2.5"
|
||||||
|
watcher:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: watcher
|
||||||
|
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.0"
|
||||||
|
web:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web
|
||||||
|
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
|
web_socket:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket
|
||||||
|
sha256: "3c12d96c0c9a4eec095246debcea7b86c0324f22df69893d538fcc6f1b8cce83"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.1.6"
|
||||||
|
web_socket_channel:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: web_socket_channel
|
||||||
|
sha256: "9f187088ed104edd8662ca07af4b124465893caf063ba29758f97af57e61da8f"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
webkit_inspection_protocol:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webkit_inspection_protocol
|
||||||
|
sha256: "87d3f2333bb240704cd3f1c6b5b7acd8a10e7f0bc28c28dcf14e782014f4a572"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.2.1"
|
||||||
|
xml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: xml
|
||||||
|
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.5.0"
|
||||||
|
yaml:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: yaml
|
||||||
|
sha256: "75769501ea3489fca56601ff33454fe45507ea3bfb014161abc3b43ae25989d5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.1.2"
|
||||||
|
sdks:
|
||||||
|
dart: ">=3.4.4 <4.0.0"
|
22
pubspec.yaml
Normal file
22
pubspec.yaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
name: dartboard_resume
|
||||||
|
description: A sample command-line application.
|
||||||
|
version: 1.0.0
|
||||||
|
# repository: https://github.com/my_org/my_repo
|
||||||
|
|
||||||
|
environment:
|
||||||
|
sdk: ^3.4.4
|
||||||
|
|
||||||
|
# Add regular dependencies here.
|
||||||
|
dependencies:
|
||||||
|
intl: ^0.19.0
|
||||||
|
lint: ^2.3.0
|
||||||
|
logging: ^1.2.0
|
||||||
|
pdf: ^3.11.1
|
||||||
|
toml: ^0.16.0
|
||||||
|
# path: ^1.8.0
|
||||||
|
|
||||||
|
dev_dependencies:
|
||||||
|
lints: ^3.0.0
|
||||||
|
test: ^1.24.0
|
||||||
|
hotreloader: ^4.2.0
|
||||||
|
|
1
test/dartboard_resume_test.dart
Normal file
1
test/dartboard_resume_test.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
Loading…
Reference in New Issue
Block a user