Skip to content

Instantly share code, notes, and snippets.

@ben953
Created June 4, 2025 19:45
Show Gist options
  • Save ben953/ba5c0840ef890840602887fb66ae4b2f to your computer and use it in GitHub Desktop.
Save ben953/ba5c0840ef890840602887fb66ae4b2f to your computer and use it in GitHub Desktop.
Sample
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
typedef EducationEntry = ({
String? degree,
String? dates,
String? school,
String? description,
});
typedef WorkExperienceEntry = ({
String? company,
String? location,
String? dates,
String? position,
String? description, // Assumed to be a multi-line string for bullet points
});
typedef ContactInfo = ({
String? phone,
String? address2,
String? address1,
String? lastName,
String? firstName,
String? email,
String? website,
List<({String? type, String? url})> socialLinks,
});
typedef SimpleEntry = ({String? itemTitle, String? itemDescription});
typedef AdditionalSectionEntry = ({
String? sectionTitle,
List<SimpleEntry> content,
});
typedef AdditionalExperienceItemEntry = ({
String? title,
String? subtitle,
String? location,
String? dates,
String? description,
});
typedef AdditionalExperienceSectionEntry = ({
String? sectionTitle,
List<AdditionalExperienceItemEntry> content,
});
class ResumeData {
final String? professionalHeadline;
final String? professionalSummary;
final List<EducationEntry> education;
final List<WorkExperienceEntry> work;
final ContactInfo contact;
final List<SimpleEntry> skills;
final List<AdditionalSectionEntry> additionalSimpleSections;
final List<AdditionalExperienceSectionEntry> additionalExperiences;
ResumeData({
required this.professionalHeadline,
required this.professionalSummary,
required this.education,
required this.work,
required this.contact,
required this.skills,
required this.additionalSimpleSections,
required this.additionalExperiences,
});
}
final sample = ResumeData(
professionalHeadline: 'Senior Software Engineer & Cloud Architect',
professionalSummary:
'Innovative senior software engineer with 8+ years of experience building scalable distributed systems and cloud-native applications. Expert in microservices architecture, cloud platforms (AWS/GCP), and machine learning engineering. Strong track record of leading engineering teams, mentoring developers, and delivering high-impact projects. Passionate about solving complex technical challenges and driving engineering excellence.',
education: [
(
degree: 'Ph.D. in Computer Science',
dates: '2022 - Present',
school: 'Stanford University',
description:
'Research focus on distributed systems and cloud computing. Published 3 papers in top-tier conferences. Teaching assistant for Advanced Algorithms course.',
),
(
degree: 'M.S. Computer Science',
dates: '2020 - 2022',
school: 'University of Washington',
description:
'Specialized in machine learning and artificial intelligence. Completed thesis on neural network optimization techniques.',
),
(
degree: 'B.S. Computer Science',
dates: '2016 - 2020',
school: 'University of Michigan',
description:
'Graduated summa cum laude with 3.95 GPA. Led undergraduate research project on parallel computing algorithms.',
),
],
work: [
(
description:
'Lead architect for cloud-native microservices platform serving millions of users. Designed and implemented scalable distributed systems using Kubernetes and AWS. Reduced infrastructure costs by 40% through optimization.\n\nManaged team of 8 engineers across 3 time zones. Established agile development practices and CI/CD pipelines that increased deployment frequency by 300%. Mentored junior developers and conducted technical interviews.',
company: 'Amazon Web Services',
location: 'Seattle, WA',
dates: '2022 - Present',
position: 'Senior Software Engineer',
),
(
description:
'Developed machine learning models for fraud detection that reduced fraudulent transactions by 60%. Built real-time data processing pipeline handling 10K+ events per second.\n\nLed migration from monolithic to microservices architecture, improving system reliability and reducing deployment time by 75%. Implemented comprehensive monitoring and alerting using Prometheus and Grafana.',
company: 'Stripe',
location: 'San Francisco, CA',
dates: '2020 - 2022',
position: 'Software Engineer',
),
(
description:
'Created React/Node.js web applications for enterprise clients. Implemented responsive UI components and RESTful APIs. Optimized database queries resulting in 40% performance improvement.\n\nCollaborated with product and design teams to deliver features on schedule. Conducted code reviews and maintained documentation. Mentored 2 junior developers.',
company: 'Microsoft',
location: 'Redmond, WA',
dates: '2018 - 2020',
position: 'Software Engineer',
),
(
description:
'Built full-stack web applications using Python/Django and React. Implemented automated testing suite that achieved 90% code coverage. Optimized front-end performance reducing load times by 50%.',
company: 'Tech Solutions Inc.',
location: 'Ann Arbor, MI',
dates: '2016 - 2018',
position: 'Software Engineer',
),
],
contact: (
phone: '555-123-4567',
address2: 'Apt 4B',
address1: '123 Main St',
lastName: 'Doe',
firstName: 'John',
email: 'john.doe@example.com',
website: 'johndoe.dev',
socialLinks: [
(type: 'LinkedIn', url: 'linkedin.com/in/johndoe'),
(type: 'GitHub', url: 'github.com/johndoe'),
],
),
skills: [
(
itemTitle: 'Cloud Platforms',
itemDescription: 'AWS, Google Cloud Platform, Azure',
),
(
itemTitle: 'Programming Languages',
itemDescription: 'Python, Java, JavaScript, Go, C++',
),
(
itemTitle: 'Web Technologies',
itemDescription: 'React, Node.js, Django, GraphQL',
),
(
itemTitle: 'DevOps & Infrastructure',
itemDescription: 'Kubernetes, Docker, Terraform, Jenkins',
),
(
itemTitle: 'Databases',
itemDescription: 'PostgreSQL, MongoDB, Redis, Elasticsearch',
),
(
itemTitle: 'Machine Learning',
itemDescription: 'TensorFlow, PyTorch, Scikit-learn',
),
(
itemTitle: 'System Design',
itemDescription: 'Microservices, Distributed Systems',
),
(itemTitle: 'Development Practices', itemDescription: 'Agile, CI/CD, TDD'),
(
itemTitle: 'Team Leadership',
itemDescription: 'Technical Leadership, Mentoring',
),
(
itemTitle: 'Problem Solving',
itemDescription: 'Algorithm Design, Performance Optimization',
),
],
additionalSimpleSections: [
(
sectionTitle: 'Awards & Recognition',
content: [
(itemTitle: 'Dean\'s List', itemDescription: 'Spring 2021, Fall 2021'),
(itemTitle: 'Innovation Award', itemDescription: null),
(
itemTitle: 'Best Technical Solution',
itemDescription: 'Company Hackathon 2022',
),
(
itemTitle: 'Distinguished Engineer',
itemDescription: 'Microsoft 2019',
),
(
itemTitle: 'Top Contributor',
itemDescription: 'Open Source Community 2021',
),
],
),
(
sectionTitle: 'Publications',
content: [
(
itemTitle: 'Scalable Machine Learning Systems',
itemDescription: 'IEEE Conference 2022',
),
(
itemTitle: 'Microservices Architecture Patterns',
itemDescription: 'ACM Journal 2021',
),
],
),
(
sectionTitle: 'Certifications',
content: [
(
itemTitle: 'AWS Solutions Architect Professional',
itemDescription: '2022',
),
(
itemTitle: 'Google Cloud Professional Architect',
itemDescription: '2021',
),
(itemTitle: 'Kubernetes Administrator (CKA)', itemDescription: '2020'),
],
),
],
additionalExperiences: [
(
sectionTitle: 'Projects',
content: [
(
title: 'Distributed Machine Learning Platform',
subtitle: 'Open Source Project',
location: 'GitHub',
dates: '2021 - Present',
description:
'Created open-source platform for distributed ML training. 1000+ GitHub stars, 50+ contributors.',
),
(
title: 'Real-time Analytics Engine',
subtitle: 'Personal Project',
location: 'Seattle, WA',
dates: '2020',
description:
'Built scalable analytics engine processing 1M+ events/day using Kafka and Spark.',
),
],
),
],
);
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: MyResume(resumeData: sample, pageMargin: 100)),
);
}
}
class CustomText extends StatelessWidget {
final String text;
final TextStyle style;
final TextAlign textAlign;
final bool bulletedList;
const CustomText(
this.text, {
super.key,
required this.style,
this.bulletedList = false,
this.textAlign = TextAlign.left,
});
@override
Widget build(BuildContext context) {
return Text(text, style: style, textAlign: textAlign);
}
}
class CustomTextWithDescription extends StatelessWidget {
final String? itemTitle;
final String? itemDescription;
final TextStyle? itemTitleStyle;
final TextStyle? itemDescriptionStyle;
final bool showBullet;
final bool oneLine;
final TextAlign textAlign;
const CustomTextWithDescription({
super.key,
this.itemTitle,
this.itemDescription,
this.itemTitleStyle,
this.itemDescriptionStyle,
required this.showBullet,
required this.oneLine,
this.textAlign = TextAlign.left,
});
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (itemTitle != null)
Text(itemTitle!, style: itemTitleStyle, textAlign: textAlign),
if (itemDescription != null)
Text(
itemDescription!,
style: itemDescriptionStyle,
textAlign: textAlign,
),
],
);
}
}
Map<String, Color> myResumeColors = {
'textPrimary': const Color(0xFF333333),
'textSecondary': const Color(0xFF555555),
'textTertiary': const Color(0xFF777777),
'divider': const Color(0xFF000000),
};
Map<String, TextStyle> myResumeTextStyles = {
'nameStyle': TextStyle(
fontFamily: 'Montserrat',
fontSize: 38.0,
fontWeight: FontWeight.w300,
color: myResumeColors['textPrimary'],
letterSpacing: 1.5,
height: 1.2,
),
'professionalHeadlineStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 12.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textSecondary'],
letterSpacing: 2.5,
height: 1.4,
),
'professionalSummaryStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 11.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textSecondary'],
height: 1.5,
),
'contactInfoStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 10.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textTertiary'],
height: 1.4,
),
'sectionTitleStyle': TextStyle(
fontFamily: 'Montserrat',
fontSize: 10.0,
fontWeight: FontWeight.w700,
color: myResumeColors['textPrimary'],
letterSpacing: 1.0,
),
'entryTitleStyle': TextStyle(
fontFamily: 'Montserrat',
fontSize: 11.0,
fontWeight: FontWeight.w700,
color: myResumeColors['textPrimary'],
letterSpacing: 0.5,
),
'entrySubtitleStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 10.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textSecondary'],
height: 1.3,
),
'descriptionStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 10.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textSecondary'],
height: 1.4,
),
'simpleItemTitleStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 10.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textSecondary'],
),
'simpleItemDescriptionStyle': TextStyle(
fontFamily: 'Lato',
fontSize: 10.0,
fontWeight: FontWeight.w400,
color: myResumeColors['textTertiary'],
height: 1.3,
),
};
class MyResume extends StatelessWidget {
final ResumeData resumeData;
final double pageMargin;
static final Color textPrimary = myResumeColors['textPrimary']!;
static final Color textSecondary = myResumeColors['textSecondary']!;
static final Color textTertiary = myResumeColors['textTertiary']!;
static final Color divider = myResumeColors['divider']!;
static final TextStyle nameStyle = myResumeTextStyles['nameStyle']!;
static final TextStyle professionalHeadlineStyle = myResumeTextStyles['professionalHeadlineStyle']!;
static final TextStyle professionalSummaryStyle = myResumeTextStyles['professionalSummaryStyle']!;
static final TextStyle contactInfoStyle = myResumeTextStyles['contactInfoStyle']!;
static final TextStyle sectionTitleStyle = myResumeTextStyles['sectionTitleStyle']!;
static final TextStyle entryTitleStyle = myResumeTextStyles['entryTitleStyle']!;
static final TextStyle entrySubtitleStyle = myResumeTextStyles['entrySubtitleStyle']!;
static final TextStyle descriptionStyle = myResumeTextStyles['descriptionStyle']!;
static final TextStyle simpleItemTitleStyle = myResumeTextStyles['simpleItemTitleStyle']!;
static final TextStyle simpleItemDescriptionStyle = myResumeTextStyles['simpleItemDescriptionStyle']!;
const MyResume({
super.key,
required this.resumeData,
required this.pageMargin,
});
String _joinStrings(List<String?> parts, {String separator = " "}) {
return parts.where((s) => s != null && s.isNotEmpty).join(separator);
}
Widget _buildHeader(ResumeData data) {
final contact = data.contact;
List<Widget> headerWidgets = [];
String nameString = _joinStrings([contact.firstName, contact.lastName]).toUpperCase();
if (nameString.isNotEmpty) {
headerWidgets.add(CustomText(
nameString,
style: nameStyle,
textAlign: TextAlign.left,
));
}
if (data.professionalHeadline?.isNotEmpty ?? false) {
if (headerWidgets.isNotEmpty) headerWidgets.add(SizedBox(height: 4.0));
headerWidgets.add(CustomText(
data.professionalHeadline!.toUpperCase(),
style: professionalHeadlineStyle,
textAlign: TextAlign.left,
));
}
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: headerWidgets);
}
Widget _buildContactDetails(ContactInfo contact) {
List<String> details = [];
if (contact.phone?.isNotEmpty ?? false) details.add(contact.phone!);
if (contact.email?.isNotEmpty ?? false) details.add(contact.email!);
String address = _joinStrings([contact.address1, contact.address2], separator: ", ");
if (address.isNotEmpty) details.add(address);
if (contact.website?.isNotEmpty ?? false) details.add(contact.website!);
for (var link in contact.socialLinks) {
if (link.url?.isNotEmpty ?? false) {
String linkText = link.url!;
if (link.type?.isNotEmpty ?? false) {
linkText = "${link.type!}: ${link.url!}";
}
details.add(linkText);
}
}
if (details.isEmpty) return SizedBox.shrink();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: details
.map((detail) => Padding(
padding: const EdgeInsets.only(bottom: 2.0),
child: CustomText(detail, style: contactInfoStyle),
))
.toList(),
);
}
Widget _buildDivider() {
return Container(
height: 1.0,
color: divider,
margin: const EdgeInsets.symmetric(vertical: 18.0));
}
Widget _buildSectionLayout({
required String title,
required List<Widget> contentItems,
}) {
return Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 110.0,
child: Padding(
padding: const EdgeInsets.only(top: 0.5),
child: CustomText(
title.toUpperCase(),
style: sectionTitleStyle,
),
),
),
SizedBox(width: 20.0),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: contentItems,
),
),
],
);
}
List<Widget> _buildWorkExperienceEntryWidgets(List<WorkExperienceEntry> workList) {
List<Widget> entryWidgets = [];
for (final work in workList) {
List<Widget> currentItemSubWidgets = [];
if (work.position?.isNotEmpty ?? false) {
currentItemSubWidgets.add(CustomText(work.position!.toUpperCase(), style: entryTitleStyle));
}
String companyAndDates = _joinStrings([work.company, work.dates], separator: " | ");
if (companyAndDates.isNotEmpty) {
if (currentItemSubWidgets.isNotEmpty) currentItemSubWidgets.add(SizedBox(height: 2.0));
currentItemSubWidgets.add(CustomText(companyAndDates, style: entrySubtitleStyle));
}
if (work.location?.isNotEmpty ?? false) {
currentItemSubWidgets.add(CustomText(work.location!, style: entrySubtitleStyle));
}
if (work.description?.isNotEmpty ?? false) {
if (currentItemSubWidgets.isNotEmpty) currentItemSubWidgets.add(SizedBox(height: 4.0));
currentItemSubWidgets.add(CustomText(work.description!, style: descriptionStyle, bulletedList: work.description!.contains('\n') && !work.description!.startsWith('•')));
}
if (currentItemSubWidgets.isNotEmpty) {
if (entryWidgets.isNotEmpty) entryWidgets.add(SizedBox(height: 16.0));
entryWidgets.add(Column(crossAxisAlignment: CrossAxisAlignment.start, children: currentItemSubWidgets));
}
}
return entryWidgets;
}
List<Widget> _buildEducationEntryWidgets(List<EducationEntry> educationList) {
List<Widget> entryWidgets = [];
for (final edu in educationList) {
List<Widget> currentItemSubWidgets = [];
if (edu.degree?.isNotEmpty ?? false) {
currentItemSubWidgets.add(CustomText(edu.degree!.toUpperCase(), style: entryTitleStyle));
}
if (edu.school?.isNotEmpty ?? false) {
if (currentItemSubWidgets.isNotEmpty) currentItemSubWidgets.add(SizedBox(height: 2.0));
currentItemSubWidgets.add(CustomText(edu.school!, style: entrySubtitleStyle));
}
if (edu.dates?.isNotEmpty ?? false) {
currentItemSubWidgets.add(CustomText(edu.dates!, style: entrySubtitleStyle));
}
if (edu.description?.isNotEmpty ?? false) {
if (currentItemSubWidgets.isNotEmpty) currentItemSubWidgets.add(SizedBox(height: 4.0));
currentItemSubWidgets.add(CustomText(edu.description!, style: descriptionStyle));
}
if (currentItemSubWidgets.isNotEmpty) {
if (entryWidgets.isNotEmpty) entryWidgets.add(SizedBox(height: 16.0));
entryWidgets.add(Column(crossAxisAlignment: CrossAxisAlignment.start, children: currentItemSubWidgets));
}
}
return entryWidgets;
}
List<Widget> _buildSkillEntryWidgets(List<SimpleEntry> skillsList) {
List<Widget> skillWidgets = [];
for (final skill in skillsList) {
if (skill.itemTitle?.isNotEmpty ?? false) {
if (skillWidgets.isNotEmpty) skillWidgets.add(SizedBox(height: 2.0));
skillWidgets.add(CustomTextWithDescription(
itemTitle: skill.itemTitle!,
itemDescription: skill.itemDescription,
itemTitleStyle: simpleItemTitleStyle,
itemDescriptionStyle: descriptionStyle,
showBullet: true,
oneLine: skill.itemDescription?.isEmpty ?? true,
));
}
}
return skillWidgets;
}
List<Widget> _buildAllAdditionalSimpleSections(List<AdditionalSectionEntry> sectionsData) {
List<Widget> allRenderedSections = [];
for (final sectionDataItem in sectionsData) {
if (sectionDataItem.sectionTitle?.isNotEmpty ?? false) {
List<Widget> contentItemWidgets = [];
for (final itemEntry in sectionDataItem.content) {
if (itemEntry.itemTitle?.isNotEmpty ?? false) {
if (contentItemWidgets.isNotEmpty) contentItemWidgets.add(SizedBox(height: 2.0));
contentItemWidgets.add(CustomTextWithDescription(
itemTitle: itemEntry.itemTitle!,
itemDescription: itemEntry.itemDescription,
itemTitleStyle: simpleItemTitleStyle,
itemDescriptionStyle: descriptionStyle,
showBullet: true,
oneLine: itemEntry.itemDescription?.isEmpty ?? true,
));
}
}
if (contentItemWidgets.isNotEmpty) {
if (allRenderedSections.isNotEmpty) allRenderedSections.add(_buildDivider());
allRenderedSections.add(_buildSectionLayout(
title: sectionDataItem.sectionTitle!,
contentItems: contentItemWidgets,
));
}
}
}
return allRenderedSections;
}
List<Widget> _buildAllAdditionalExperienceSections(List<AdditionalExperienceSectionEntry> sectionsData) {
List<Widget> allRenderedSections = [];
for (final sectionEntryItem in sectionsData) {
if (sectionEntryItem.sectionTitle?.isNotEmpty ?? false) {
List<Widget> experienceItemWidgets = [];
for (final item in sectionEntryItem.content) {
List<Widget> currentSubWidgets = [];
if (item.title?.isNotEmpty ?? false) {
currentSubWidgets.add(CustomText(item.title!.toUpperCase(), style: entryTitleStyle));
}
String subtitleAndDates = _joinStrings([item.subtitle, item.dates], separator: " | ");
if (subtitleAndDates.isNotEmpty) {
if (currentSubWidgets.isNotEmpty) currentSubWidgets.add(SizedBox(height: 2.0));
currentSubWidgets.add(CustomText(subtitleAndDates, style: entrySubtitleStyle));
}
if (item.location?.isNotEmpty ?? false) {
currentSubWidgets.add(CustomText(item.location!, style: entrySubtitleStyle));
}
if (item.description?.isNotEmpty ?? false) {
if (currentSubWidgets.isNotEmpty) currentSubWidgets.add(SizedBox(height: 4.0));
currentSubWidgets.add(CustomText(item.description!, style: descriptionStyle, bulletedList: item.description!.contains('\n') && !item.description!.startsWith('•')));
}
if (currentSubWidgets.isNotEmpty) {
if (experienceItemWidgets.isNotEmpty) experienceItemWidgets.add(SizedBox(height: 16.0));
experienceItemWidgets.add(Column(crossAxisAlignment: CrossAxisAlignment.start, children: currentSubWidgets));
}
}
if (experienceItemWidgets.isNotEmpty) {
if (allRenderedSections.isNotEmpty) allRenderedSections.add(_buildDivider());
allRenderedSections.add(_buildSectionLayout(
title: sectionEntryItem.sectionTitle!,
contentItems: experienceItemWidgets,
));
}
}
}
return allRenderedSections;
}
@override
Widget build(BuildContext context) {
List<Widget> children = [];
Widget header = _buildHeader(resumeData);
if (header is Column && header.children.isNotEmpty || header is! Column && header is! SizedBox) {
children.add(header);
}
Widget contactDetails = _buildContactDetails(resumeData.contact);
if (contactDetails is Column && contactDetails.children.isNotEmpty || contactDetails is! Column && contactDetails is! SizedBox) {
if (children.isNotEmpty) children.add(SizedBox(height: 8.0));
children.add(contactDetails);
}
if (resumeData.professionalSummary?.isNotEmpty ?? false) {
if (children.isNotEmpty) children.add(SizedBox(height: 16.0));
children.add(CustomText(resumeData.professionalSummary!, style: professionalSummaryStyle));
}
if (children.isNotEmpty) { // Add a divider if any header/contact/summary was added
children.add(_buildDivider());
}
bool previousSectionBlockAdded = false; // Tracks if a major section block *that requires a divider before the next* was added.
if (resumeData.work.isNotEmpty) {
final List<Widget> workEntryWidgets = _buildWorkExperienceEntryWidgets(resumeData.work);
if (workEntryWidgets.isNotEmpty) {
if (previousSectionBlockAdded) children.add(_buildDivider());
children.add(_buildSectionLayout(title: "Experience", contentItems: workEntryWidgets));
previousSectionBlockAdded = true;
}
}
if (resumeData.education.isNotEmpty) {
final List<Widget> educationEntryWidgets = _buildEducationEntryWidgets(resumeData.education);
if (educationEntryWidgets.isNotEmpty) {
if (previousSectionBlockAdded) children.add(_buildDivider());
children.add(_buildSectionLayout(title: "Education", contentItems: educationEntryWidgets));
previousSectionBlockAdded = true;
}
}
if (resumeData.skills.isNotEmpty) {
final List<Widget> skillEntryWidgets = _buildSkillEntryWidgets(resumeData.skills);
if (skillEntryWidgets.isNotEmpty) {
if (previousSectionBlockAdded) children.add(_buildDivider());
children.add(_buildSectionLayout(title: "Skills", contentItems: skillEntryWidgets));
previousSectionBlockAdded = true;
}
}
if (resumeData.additionalSimpleSections.isNotEmpty) {
final List<Widget> additionalSimpleSectionWidgets = _buildAllAdditionalSimpleSections(resumeData.additionalSimpleSections);
if (additionalSimpleSectionWidgets.isNotEmpty) {
if (previousSectionBlockAdded) children.add(_buildDivider());
children.addAll(additionalSimpleSectionWidgets);
previousSectionBlockAdded = true;
}
}
if (resumeData.additionalExperiences.isNotEmpty) {
final List<Widget> additionalExperienceWidgets = _buildAllAdditionalExperienceSections(resumeData.additionalExperiences);
if (additionalExperienceWidgets.isNotEmpty) {
if (previousSectionBlockAdded) children.add(_buildDivider());
children.addAll(additionalExperienceWidgets);
previousSectionBlockAdded = true;
}
}
if (children.isNotEmpty && children.last is Container && (children.last as Container).margin != null) {
// Remove trailing divider if it's the last element
final lastWidget = children.last as Container;
if (lastWidget.color == divider && lastWidget.constraints?.maxHeight == 1.0){
children.removeLast();
}
}
return Padding(
padding: EdgeInsets.all(pageMargin),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: children,
),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment