SlideShare ist ein Scribd-Unternehmen logo
1 von 38
Downloaden Sie, um offline zu lesen
Supercharge Flutter
Declarative UI with code
generation
Emanuele Papa
droidcon London 2021
Working at Zest One in Chiasso, Switzerland
Who I am?
Emanuele Papa, Android Developer
Find me at www.emanuelepapa.dev
Declarative UI
Imperative UI -> Declarative UI
Jetpack Compose and SwiftUI
Unfortunately, not perfect yet
No more XML or UIKit
Padding in Flutter
Padding(
padding: EdgeInsets.all(16.0),
child: Text("Hello droidcon!")
);
What we want
- Make the code easy to write
- Avoid errors caused by distraction
- Minimize code duplication
- Make the IDE our best friend
- Improve our productivity
Looking for improvements
Someone else experienced the same struggle
Some libraries are available on GitHub
It's an improvement, but you still need to add the
Padding value manually
The missing thing
PaddingTop(16.0, child: Text("Hello droidcon!"));
Design System Padding
No need to add the Padding value manually,
it's specified in the class name
MediumTopPadding(child: Text("Hello droidcon!"));
How to create these
widgets?
Paddinger
How to use Paddinger?
dependencies:
paddinger_annotations: [latestVersionHere]
dev_dependencies:
paddinger: [latestVersionHere]
Add these dependencies to your pubspec.yaml
How to use Paddinger?
Create a paddings.dart file which contains your
PADDING_ definitions
@paddinger
const double PADDING_MEDIUM = 16.0;
@paddinger
const double PADDING_LARGE = 24.0;
How to use Paddinger?
Add material or cupertino import
Add part directive
// ignore: unused_import
import 'package:flutter/material.dart';
part 'paddings.g.dart';
Start the code generation
Now run
flutter pub run build_runner build --delete-conflicting-
outputs
What's the result?
MediumAllPadding
MediumLeftPadding
MediumTopPadding
MediumRightPadding
MediumBottomPadding
MediumHorizontalPadding
MediumVerticalPadding
MediumLeftTopPadding
MediumLeftBottomPadding
MediumRightTopPadding
MediumRightBottomPadding
paddings.g.dart
LargeAllPadding
LargeLeftPadding
LargeTopPadding
LargeRightPadding
LargeBottomPadding
LargeHorizontalPadding
LargeVerticalPadding
LargeLeftTopPadding
LargeLeftBottomPadding
LargeRightTopPadding
LargeRightBottomPadding
What's the result?
class MediumAllPadding extends Padding {
const MediumAllPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.all(PADDING_MEDIUM),
child: child);
}
Do not add it to your version control system
How to use them
Just import paddings.dart in your widgets,
it also contains all the generated classes created in
paddings.g.dart
Let's deep dive inside
paddinger source code!
Paddinger source code
Monorepo with 2 projects:
- paddinger
- paddinger_annotations
Paddinger source code
///Annotation used by paddinger to identify PADDING_ constants
class Paddinger {
const Paddinger();
}
///Helper object for [Paddinger] annotation
const paddinger = Paddinger();
paddinger.dart
Paddinger source code
dependencies:
analyzer: ^1.5.0
build: ^2.0.0
source_gen: ^1.0.0
recase: ^4.0.0
paddinger_annotations: ^0.1.1
#local development
#paddinger_annotations:
# path: ../paddinger_annotations/
dev_dependencies:
test: 1.16.8
pubspec.yaml
Paddinger source code
builders:
paddinger_generator:
import: "package:paddinger/paddinger.dart"
builder_factories: ["paddingerGenerator"]
build_extensions: {".dart": [".paddinger.g.part"]}
build.yaml
Paddinger source code
///Paddinger generator used with [Builder]
Builder paddingerGenerator(BuilderOptions options) =>
SharedPartBuilder([PaddingerGenerator()],
'paddinger_generator');


paddinger.dart
Paddinger source code
class PaddingerGenerator extends GeneratorForAnnotation<Paddinger> {
@override
FutureOr<String> generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
final constantName = element.name!;
validatePaddingConstantName(constantName);
final generatedName = toNameForGeneration(constantName);
return generatePaddingWidgets(generatedName, constantName);
}
}
paddinger_generator.dart
Paddinger source code
String generatePaddingWidgets(String paddingName, String constantName) {
return '''
${_addStartComment(paddingName)}
${_addAllPadding(paddingName, constantName)}
${_addOnlyPaddings(paddingName, constantName)}
${_addSymmetricPaddings(paddingName, constantName)}
${_addMissingCombinationPaddings(paddingName, constantName)}
${_addEndComment(paddingName)}
''';
}
Paddinger source code
String _addAllPadding(String paddingName, String constantName) {
return '''
class ${paddingName}AllPadding extends Padding {
const ${paddingName}AllPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.all($constantName),
child: child);
}
''';
}
Paddinger source code
class MediumAllPadding extends Padding {
const MediumAllPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.all(PADDING_MEDIUM),
child: child);
}
Paddinger source code
String _addOnlyPaddings(String paddingName, String constantName) {
final onlyPaddingKeys = PaddingDirection.values
.map((paddingDirection) => paddingDirection.asPascalCase);
final onlyPaddingWidgets = onlyPaddingKeys.map((paddingKey) => '''
class $paddingName${paddingKey}Padding extends Padding {
const $paddingName${paddingKey}Padding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.only(${paddingKey.toLowerCase()}:
$constantName),
child: child);
}
''').toList();
return onlyPaddingWidgets.join();
}
Paddinger source code
class MediumLeftPadding extends Padding {
const MediumLeftPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.only(left: PADDING_MEDIUM),
child: child);
}
class MediumTopPadding extends Padding {
const MediumTopPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.only(top: PADDING_MEDIUM),
child: child);
}
///two more classes: MediumRightPadding and MediumBottomPadding
How can you test the
generated code?
Test the generated code
test(
'GIVEN a valid padding constant name, WHEN validatePaddingConstantName(), THEN it
returns normally',
() {
expect(
() => validatePaddingConstantName("PADDING_MEDIUM"), returnsNormally);
});
test(
'GIVEN a not valid padding constant name, WHEN validatePaddingConstantName(),
THEN an exception is thrown',
() {
expect(() => validatePaddingConstantName("PADDIN_MEDIUM"),
throwsA(isA<Exception>()));
});
Test the generated code
test(
'GIVEN a valid padding constant name, WHEN toNameForGeneration(), THEN a
valid name is generated',
() {
expect(toNameForGeneration("PADDING_MEDIUM"), "Medium");
});
test(
'GIVEN a valid padding constant name with two underscores, WHEN
toNameForGeneration(), THEN a valid name is generated',
() {
expect(toNameForGeneration("PADDING_VERY_LARGE"), "VeryLarge");
});
Test the generated code
test(
'GIVEN a valid paddingName and a valid constantName, WHEN generatePaddingWidgets(), THEN valid padding widgets are
generated',
() {
expect(generatePaddingWidgets("Medium", "PADDING_MEDIUM"), '''
// **************************************************************************
// START Medium
// **************************************************************************
class MediumAllPadding extends Padding {
const MediumAllPadding({Key? key, required Widget child})
: super(
key: key,
padding: const EdgeInsets.all(PADDING_MEDIUM),
child: child);
}
///Other classes here, this line is not part of the real generated code
''');
});
Nice helpful tips
IDE code completion will be able to:
- suggest you all the available Padding classes
- transforms TLMP into TopLeftMediumPadding
Can you generate
whatever you want?
Yes!
Don't limit your
imagination!
Thank you!
Drop a line to info@zest.one
Get in touch with me
https://www.emanuelepapa.dev
We are hiring @ ZestOne

Weitere ähnliche Inhalte

Ähnlich wie Supercharge Flutter declarative UI with code generation

Dart for Java Developers
Dart for Java DevelopersDart for Java Developers
Dart for Java DevelopersYakov Fain
 
Behavioural Driven Development in Zf2
Behavioural Driven Development in Zf2Behavioural Driven Development in Zf2
Behavioural Driven Development in Zf2David Contavalli
 
Code Quality Practice and Tools
Code Quality Practice and ToolsCode Quality Practice and Tools
Code Quality Practice and ToolsBob Paulin
 
Developer Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersDeveloper Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersJiaxuan Lin
 
Dsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in ScalaDsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in ScalaUgo Matrangolo
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsAdégòkè Obasá
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF SummitOrtus Solutions, Corp
 
Cordova iOS Native Plugin Development
Cordova iOS Native Plugin DevelopmentCordova iOS Native Plugin Development
Cordova iOS Native Plugin DevelopmentJosue Bustos
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Fafadia Tech
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best PracticesYekmer Simsek
 

Ähnlich wie Supercharge Flutter declarative UI with code generation (20)

Coding Naked 2023
Coding Naked 2023Coding Naked 2023
Coding Naked 2023
 
Dart for Java Developers
Dart for Java DevelopersDart for Java Developers
Dart for Java Developers
 
Android For All The Things
Android For All The ThingsAndroid For All The Things
Android For All The Things
 
Behavioural Driven Development in Zf2
Behavioural Driven Development in Zf2Behavioural Driven Development in Zf2
Behavioural Driven Development in Zf2
 
Code Quality Practice and Tools
Code Quality Practice and ToolsCode Quality Practice and Tools
Code Quality Practice and Tools
 
Wtf per lineofcode
Wtf per lineofcodeWtf per lineofcode
Wtf per lineofcode
 
Developer Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for BeginnersDeveloper Student Clubs NUK - Flutter for Beginners
Developer Student Clubs NUK - Flutter for Beginners
 
Choose flutter
Choose flutterChoose flutter
Choose flutter
 
Dsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in ScalaDsug 05 02-15 - ScalDI - lightweight DI in Scala
Dsug 05 02-15 - ScalDI - lightweight DI in Scala
 
IndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web AppsIndexedDB and Push Notifications in Progressive Web Apps
IndexedDB and Push Notifications in Progressive Web Apps
 
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
3 Ways to test your ColdFusion API - 2017 Adobe CF Summit
 
IOC + Javascript
IOC + JavascriptIOC + Javascript
IOC + Javascript
 
appledoc_style
appledoc_styleappledoc_style
appledoc_style
 
Cordova iOS Native Plugin Development
Cordova iOS Native Plugin DevelopmentCordova iOS Native Plugin Development
Cordova iOS Native Plugin Development
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
CDI @javaonehyderabad
CDI @javaonehyderabadCDI @javaonehyderabad
CDI @javaonehyderabad
 
Bronx study jam 1
Bronx study jam 1Bronx study jam 1
Bronx study jam 1
 
Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)Introduction To Google Android (Ft Rohan Bomle)
Introduction To Google Android (Ft Rohan Bomle)
 
Excelian hyperledger walkthrough-feb17
Excelian hyperledger walkthrough-feb17Excelian hyperledger walkthrough-feb17
Excelian hyperledger walkthrough-feb17
 
Android Best Practices
Android Best PracticesAndroid Best Practices
Android Best Practices
 

Kürzlich hochgeladen

Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Conceptsthomashtkim
 
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with Graph
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with GraphGraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with Graph
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with GraphNeo4j
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfWSO2
 
^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto
^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto
^Clinic ^%[+27788225528*Abortion Pills For Sale In sowetokasambamuno
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024MulesoftMunichMeetup
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdftimtebeek1
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024SimonedeGijt
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Lisi Hocke
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Henry Schreiner
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksJinanKordab
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Andreas Granig
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...naitiksharma1124
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaNeo4j
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckMarc Lester
 
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Flutter Agency
 
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanWorkshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanNeo4j
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfkalichargn70th171
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletAndrea Goulet
 

Kürzlich hochgeladen (20)

Encryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key ConceptsEncryption Recap: A Refresher on Key Concepts
Encryption Recap: A Refresher on Key Concepts
 
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with Graph
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with GraphGraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with Graph
GraphSummit Milan & Stockholm - Neo4j: The Art of the Possible with Graph
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdf
 
^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto
^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto
^Clinic ^%[+27788225528*Abortion Pills For Sale In soweto
 
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
Anypoint Code Builder - Munich MuleSoft Meetup - 16th May 2024
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdf
 
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
 
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
Wired_2.0_CREATE YOUR ULTIMATE LEARNING ENVIRONMENT_JCON_16052024
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024
 
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
Abortion Clinic In Pretoria ](+27832195400*)[ 🏥 Safe Abortion Pills in Pretor...
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with Links
 
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024Automate your OpenSIPS config tests - OpenSIPS Summit 2024
Automate your OpenSIPS config tests - OpenSIPS Summit 2024
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
 
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale IbridaUNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
UNI DI NAPOLI FEDERICO II - Il ruolo dei grafi nell'AI Conversazionale Ibrida
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
 
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
Navigation in flutter – how to add stack, tab, and drawer navigators to your ...
 
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit MilanWorkshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
Workshop: Enabling GenAI Breakthroughs with Knowledge Graphs - GraphSummit Milan
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea Goulet
 

Supercharge Flutter declarative UI with code generation

  • 1. Supercharge Flutter Declarative UI with code generation Emanuele Papa droidcon London 2021
  • 2. Working at Zest One in Chiasso, Switzerland Who I am? Emanuele Papa, Android Developer Find me at www.emanuelepapa.dev
  • 3. Declarative UI Imperative UI -> Declarative UI Jetpack Compose and SwiftUI Unfortunately, not perfect yet No more XML or UIKit
  • 4. Padding in Flutter Padding( padding: EdgeInsets.all(16.0), child: Text("Hello droidcon!") );
  • 5. What we want - Make the code easy to write - Avoid errors caused by distraction - Minimize code duplication - Make the IDE our best friend - Improve our productivity
  • 6. Looking for improvements Someone else experienced the same struggle Some libraries are available on GitHub
  • 7. It's an improvement, but you still need to add the Padding value manually The missing thing PaddingTop(16.0, child: Text("Hello droidcon!"));
  • 8. Design System Padding No need to add the Padding value manually, it's specified in the class name MediumTopPadding(child: Text("Hello droidcon!"));
  • 9. How to create these widgets?
  • 11. How to use Paddinger? dependencies: paddinger_annotations: [latestVersionHere] dev_dependencies: paddinger: [latestVersionHere] Add these dependencies to your pubspec.yaml
  • 12. How to use Paddinger? Create a paddings.dart file which contains your PADDING_ definitions @paddinger const double PADDING_MEDIUM = 16.0; @paddinger const double PADDING_LARGE = 24.0;
  • 13. How to use Paddinger? Add material or cupertino import Add part directive // ignore: unused_import import 'package:flutter/material.dart'; part 'paddings.g.dart';
  • 14. Start the code generation Now run flutter pub run build_runner build --delete-conflicting- outputs
  • 16. What's the result? class MediumAllPadding extends Padding { const MediumAllPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.all(PADDING_MEDIUM), child: child); }
  • 17. Do not add it to your version control system How to use them Just import paddings.dart in your widgets, it also contains all the generated classes created in paddings.g.dart
  • 18. Let's deep dive inside paddinger source code!
  • 19. Paddinger source code Monorepo with 2 projects: - paddinger - paddinger_annotations
  • 20. Paddinger source code ///Annotation used by paddinger to identify PADDING_ constants class Paddinger { const Paddinger(); } ///Helper object for [Paddinger] annotation const paddinger = Paddinger(); paddinger.dart
  • 21. Paddinger source code dependencies: analyzer: ^1.5.0 build: ^2.0.0 source_gen: ^1.0.0 recase: ^4.0.0 paddinger_annotations: ^0.1.1 #local development #paddinger_annotations: # path: ../paddinger_annotations/ dev_dependencies: test: 1.16.8 pubspec.yaml
  • 22. Paddinger source code builders: paddinger_generator: import: "package:paddinger/paddinger.dart" builder_factories: ["paddingerGenerator"] build_extensions: {".dart": [".paddinger.g.part"]} build.yaml
  • 23. Paddinger source code ///Paddinger generator used with [Builder] Builder paddingerGenerator(BuilderOptions options) => SharedPartBuilder([PaddingerGenerator()], 'paddinger_generator'); paddinger.dart
  • 24. Paddinger source code class PaddingerGenerator extends GeneratorForAnnotation<Paddinger> { @override FutureOr<String> generateForAnnotatedElement( Element element, ConstantReader annotation, BuildStep buildStep) { final constantName = element.name!; validatePaddingConstantName(constantName); final generatedName = toNameForGeneration(constantName); return generatePaddingWidgets(generatedName, constantName); } } paddinger_generator.dart
  • 25. Paddinger source code String generatePaddingWidgets(String paddingName, String constantName) { return ''' ${_addStartComment(paddingName)} ${_addAllPadding(paddingName, constantName)} ${_addOnlyPaddings(paddingName, constantName)} ${_addSymmetricPaddings(paddingName, constantName)} ${_addMissingCombinationPaddings(paddingName, constantName)} ${_addEndComment(paddingName)} '''; }
  • 26. Paddinger source code String _addAllPadding(String paddingName, String constantName) { return ''' class ${paddingName}AllPadding extends Padding { const ${paddingName}AllPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.all($constantName), child: child); } '''; }
  • 27. Paddinger source code class MediumAllPadding extends Padding { const MediumAllPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.all(PADDING_MEDIUM), child: child); }
  • 28. Paddinger source code String _addOnlyPaddings(String paddingName, String constantName) { final onlyPaddingKeys = PaddingDirection.values .map((paddingDirection) => paddingDirection.asPascalCase); final onlyPaddingWidgets = onlyPaddingKeys.map((paddingKey) => ''' class $paddingName${paddingKey}Padding extends Padding { const $paddingName${paddingKey}Padding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.only(${paddingKey.toLowerCase()}: $constantName), child: child); } ''').toList(); return onlyPaddingWidgets.join(); }
  • 29. Paddinger source code class MediumLeftPadding extends Padding { const MediumLeftPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.only(left: PADDING_MEDIUM), child: child); } class MediumTopPadding extends Padding { const MediumTopPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.only(top: PADDING_MEDIUM), child: child); } ///two more classes: MediumRightPadding and MediumBottomPadding
  • 30. How can you test the generated code?
  • 31. Test the generated code test( 'GIVEN a valid padding constant name, WHEN validatePaddingConstantName(), THEN it returns normally', () { expect( () => validatePaddingConstantName("PADDING_MEDIUM"), returnsNormally); }); test( 'GIVEN a not valid padding constant name, WHEN validatePaddingConstantName(), THEN an exception is thrown', () { expect(() => validatePaddingConstantName("PADDIN_MEDIUM"), throwsA(isA<Exception>())); });
  • 32. Test the generated code test( 'GIVEN a valid padding constant name, WHEN toNameForGeneration(), THEN a valid name is generated', () { expect(toNameForGeneration("PADDING_MEDIUM"), "Medium"); }); test( 'GIVEN a valid padding constant name with two underscores, WHEN toNameForGeneration(), THEN a valid name is generated', () { expect(toNameForGeneration("PADDING_VERY_LARGE"), "VeryLarge"); });
  • 33. Test the generated code test( 'GIVEN a valid paddingName and a valid constantName, WHEN generatePaddingWidgets(), THEN valid padding widgets are generated', () { expect(generatePaddingWidgets("Medium", "PADDING_MEDIUM"), ''' // ************************************************************************** // START Medium // ************************************************************************** class MediumAllPadding extends Padding { const MediumAllPadding({Key? key, required Widget child}) : super( key: key, padding: const EdgeInsets.all(PADDING_MEDIUM), child: child); } ///Other classes here, this line is not part of the real generated code '''); });
  • 34. Nice helpful tips IDE code completion will be able to: - suggest you all the available Padding classes - transforms TLMP into TopLeftMediumPadding
  • 38. Drop a line to info@zest.one Get in touch with me https://www.emanuelepapa.dev We are hiring @ ZestOne