basic setup (layout + icons)
This commit is contained in:
5
flutter/deps/font_awesome_flutter/util/configurator.bat
Normal file
5
flutter/deps/font_awesome_flutter/util/configurator.bat
Normal file
@@ -0,0 +1,5 @@
|
||||
@echo off
|
||||
pushd %~dp0
|
||||
cd ..
|
||||
dart .\util\lib\main.dart %* & ^
|
||||
popd
|
5
flutter/deps/font_awesome_flutter/util/configurator.sh
Executable file
5
flutter/deps/font_awesome_flutter/util/configurator.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
pushd "$(dirname "$0")" > /dev/null || exit
|
||||
cd ..
|
||||
dart ./util/lib/main.dart "$@"
|
||||
popd > /dev/null || exit
|
663
flutter/deps/font_awesome_flutter/util/lib/main.dart
Normal file
663
flutter/deps/font_awesome_flutter/util/lib/main.dart
Normal file
@@ -0,0 +1,663 @@
|
||||
// ignore_for_file: avoid_print
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:ansicolor/ansicolor.dart';
|
||||
import 'package:args/args.dart';
|
||||
import 'package:recase/recase.dart';
|
||||
import 'package:version/version.dart';
|
||||
import 'package:pub_semver/pub_semver.dart' as pub;
|
||||
|
||||
/// A map which adjusts icon ids starting with a number
|
||||
///
|
||||
/// Some icons cannot keep their id as identifier, as dart does not allow
|
||||
/// numbers as the beginning of a variable names. The chosen solution is, to
|
||||
/// write those parts out.
|
||||
const Map<String, String> nameAdjustments = {
|
||||
"500px": "fiveHundredPx",
|
||||
"360-degrees": "threeHundredSixtyDegrees",
|
||||
"1": "one",
|
||||
"2": "two",
|
||||
"3": "three",
|
||||
"4": "four",
|
||||
"5": "five",
|
||||
"6": "six",
|
||||
"7": "seven",
|
||||
"8": "eight",
|
||||
"9": "nine",
|
||||
"0": "zero",
|
||||
"42-group": "fortyTwoGroup",
|
||||
"00": "zeroZero",
|
||||
// found in aliases
|
||||
"100": "hundred",
|
||||
};
|
||||
|
||||
/// Some aliases clash with reserved words of dartlang. Those are ignored.
|
||||
const List<String> ignoredAliases = ["try"];
|
||||
|
||||
/// Generated by [readAndPickMetadata] for each icon
|
||||
class IconMetadata {
|
||||
final String name;
|
||||
final String label;
|
||||
final String unicode;
|
||||
final List<String> searchTerms;
|
||||
final List<String> styles;
|
||||
final List<String> aliases;
|
||||
|
||||
IconMetadata(
|
||||
this.name,
|
||||
this.label,
|
||||
this.unicode,
|
||||
this.searchTerms,
|
||||
this.styles,
|
||||
this.aliases,
|
||||
);
|
||||
}
|
||||
|
||||
final AnsiPen red = AnsiPen()..xterm(009);
|
||||
final AnsiPen blue = AnsiPen()..xterm(012);
|
||||
final AnsiPen yellow = AnsiPen()..xterm(011);
|
||||
|
||||
/// Utility program to customize font awesome flutter
|
||||
///
|
||||
/// For usage information see [displayHelp]
|
||||
///
|
||||
/// Steps:
|
||||
/// 1. Check if icons.json exists in project root (or in lib/fonts)
|
||||
/// if icons.json does not exist:
|
||||
/// 1.1 download official, free icons.json from github
|
||||
/// https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/metadata/icons.json
|
||||
/// 1.2 download official, free icons and replace existing
|
||||
/// https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-brands-400.ttf
|
||||
/// https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-regular-400.ttf
|
||||
/// https://raw.githubusercontent.com/FortAwesome/Font-Awesome/master/webfonts/fa-solid-900.ttf
|
||||
/// 3. filter out unwanted icon styles
|
||||
/// 4. build icons, example
|
||||
/// if dynamic icons requested:
|
||||
/// 4.1 create map
|
||||
/// 5. format all generated files
|
||||
/// 6. if icons.json was downloaded by this tool, remove icons.json
|
||||
void main(List<String> rawArgs) async {
|
||||
print(blue('''
|
||||
#### # #####################################################################
|
||||
### ### ############ Font Awesome Flutter Configurator ######################
|
||||
# # # #####################################################################
|
||||
'''));
|
||||
|
||||
final argParser = setUpArgParser();
|
||||
final args = argParser.parse(rawArgs);
|
||||
|
||||
if (args['help']) {
|
||||
displayHelp(argParser);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
await printVersionNotice('fluttercommunity/font_awesome_flutter');
|
||||
|
||||
File iconsJson = File('lib/fonts/icons.json');
|
||||
final hasCustomIconsJson = iconsJson.existsSync();
|
||||
|
||||
if (!hasCustomIconsJson) {
|
||||
print(blue('No icons.json found, updating free icons'));
|
||||
const repositoryName = 'FortAwesome/Font-Awesome';
|
||||
final defaultBranch = await getRepositoryDefaultBranch(repositoryName);
|
||||
print(blue(
|
||||
'Choosing branch "$defaultBranch" of repository https://github.com/$repositoryName'));
|
||||
await download(
|
||||
'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/$defaultBranch/metadata/icons.json',
|
||||
File('lib/fonts/icons.json'));
|
||||
await download(
|
||||
'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/$defaultBranch/webfonts/fa-brands-400.ttf',
|
||||
File('lib/fonts/fa-brands-400.ttf'));
|
||||
await download(
|
||||
'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/$defaultBranch/webfonts/fa-regular-400.ttf',
|
||||
File('lib/fonts/fa-regular-400.ttf'));
|
||||
await download(
|
||||
'https://raw.githubusercontent.com/FortAwesome/Font-Awesome/$defaultBranch/webfonts/fa-solid-900.ttf',
|
||||
File('lib/fonts/fa-solid-900.ttf'));
|
||||
} else {
|
||||
print(blue('Custom icons.json found, generating files'));
|
||||
}
|
||||
|
||||
// A list of all versions mentioned in the metadata
|
||||
final List<String> versions = [];
|
||||
final List<IconMetadata> metadata = [];
|
||||
final Set<String> styles = {};
|
||||
// duotone icons are no longer supported
|
||||
final List<String> excludedStyles = ['duotone', ...args['exclude']];
|
||||
var hasDuotoneIcons = readAndPickMetadata(
|
||||
iconsJson, metadata, styles, versions, excludedStyles);
|
||||
if (hasDuotoneIcons) {
|
||||
// Duotone are no longer supported - temporarily added notice to avoid
|
||||
// confusion
|
||||
print(red(
|
||||
'Duotone icons are no longer supported. Automatically disabled them.'));
|
||||
}
|
||||
hasDuotoneIcons = false;
|
||||
|
||||
final highestVersion = calculateFontAwesomeVersion(versions);
|
||||
|
||||
print(blue('\nGenerating icon definitions'));
|
||||
writeCodeToFile(
|
||||
() => generateIconDefinitionClass(metadata, highestVersion),
|
||||
'lib/font_awesome_flutter.dart',
|
||||
);
|
||||
|
||||
print(blue('\nGenerating example code'));
|
||||
writeCodeToFile(
|
||||
() => generateExamplesListClass(metadata),
|
||||
'example/lib/icons.dart',
|
||||
);
|
||||
|
||||
if (args['dynamic']) {
|
||||
writeCodeToFile(
|
||||
() => generateIconNameMap(metadata),
|
||||
'lib/name_icon_mapping.dart',
|
||||
);
|
||||
} else {
|
||||
// Remove file if dynamic is not requested. Helps things to stay consistent
|
||||
final iconNameMappingFile = File('lib/name_icon_mapping.dart');
|
||||
if (iconNameMappingFile.existsSync()) iconNameMappingFile.deleteSync();
|
||||
}
|
||||
|
||||
adjustPubspecFontIncludes(styles);
|
||||
|
||||
if (!hasCustomIconsJson) {
|
||||
iconsJson.deleteSync();
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns this package's current version
|
||||
String getPackageVersion() {
|
||||
var pubspecFile = File('pubspec.yaml');
|
||||
var pubspec = pubspecFile.readAsLinesSync();
|
||||
for (final line in pubspec) {
|
||||
if (line.startsWith('version:')) {
|
||||
return line.substring('version'.length + 1).trim();
|
||||
}
|
||||
}
|
||||
return 'no version found';
|
||||
}
|
||||
|
||||
/// Automatically (un)comments font definitions in pubspec.yaml
|
||||
void adjustPubspecFontIncludes(Set<String> styles) {
|
||||
var pubspecFile = File('pubspec.yaml');
|
||||
var pubspec = pubspecFile.readAsLinesSync();
|
||||
String styleName;
|
||||
Set<String> enabledStyles = {};
|
||||
|
||||
var startFlutterSection = pubspec.indexOf('flutter:');
|
||||
String line;
|
||||
for (var i = startFlutterSection; i < pubspec.length; i++) {
|
||||
line = uncommentYamlLine(pubspec[i]);
|
||||
if (!line.trimLeft().startsWith('- family:')) continue;
|
||||
|
||||
styleName = line.substring(25).toLowerCase(); // - family: FontAwesomeXXXXXX
|
||||
if (styles.contains(styleName)) {
|
||||
pubspec[i] = uncommentYamlLine(pubspec[i]);
|
||||
pubspec[i + 1] = uncommentYamlLine(pubspec[i + 1]);
|
||||
pubspec[i + 2] = uncommentYamlLine(pubspec[i + 2]);
|
||||
pubspec[i + 3] = uncommentYamlLine(pubspec[i + 3]);
|
||||
enabledStyles.add(styleName);
|
||||
} else {
|
||||
pubspec[i] = commentYamlLine(pubspec[i]);
|
||||
pubspec[i + 1] = commentYamlLine(pubspec[i + 1]);
|
||||
pubspec[i + 2] = commentYamlLine(pubspec[i + 2]);
|
||||
pubspec[i + 3] = commentYamlLine(pubspec[i + 3]);
|
||||
}
|
||||
i = i + 3; // + 4 with i++
|
||||
}
|
||||
|
||||
pubspecFile.writeAsStringSync(pubspec.join('\n'));
|
||||
|
||||
print(blue('\nFound and enabled the following icon styles:'));
|
||||
enabledStyles.isEmpty
|
||||
? print(red("None"))
|
||||
: print(blue(enabledStyles.join(', ')));
|
||||
|
||||
print(blue('\nRunning "flutter pub get"'));
|
||||
final result = Process.runSync('flutter', ['pub', 'get'], runInShell: true);
|
||||
stdout.write(result.stdout);
|
||||
stderr.write(red(result.stderr));
|
||||
|
||||
print(blue('\nDone'));
|
||||
}
|
||||
|
||||
/// Comments out a line of yaml code. Does nothing if already commented
|
||||
String commentYamlLine(String line) {
|
||||
if (line.startsWith('#')) return line;
|
||||
return '#$line';
|
||||
}
|
||||
|
||||
/// Uncomments a line of yaml code. Does nothing if not commented.
|
||||
///
|
||||
/// Expects the rest of the line to be valid yaml and to have the correct
|
||||
/// indention after removing the first #.
|
||||
String uncommentYamlLine(String line) {
|
||||
if (!line.startsWith('#')) return line;
|
||||
return line.substring(1);
|
||||
}
|
||||
|
||||
/// Writes lines of code created by a [generator] to [filePath] and formats it
|
||||
void writeCodeToFile(List<String> Function() generator, String filePath) {
|
||||
List<String> generated = generator();
|
||||
File(filePath).writeAsStringSync(generated.join('\n'));
|
||||
final result = Process.runSync('dart', ['format', filePath]);
|
||||
stdout.write(result.stdout);
|
||||
stderr.write(red(result.stderr));
|
||||
}
|
||||
|
||||
/// Enables the use of a map to dynamically load icons by their name
|
||||
///
|
||||
/// To use, import:
|
||||
/// `import 'package:font_awesome_flutter/name_icon_mapping.dart'`
|
||||
/// And then either use faIconNameMapping directly to look up specific icons,
|
||||
/// or use the getIconFromCss helper function.
|
||||
List<String> generateIconNameMap(List<IconMetadata> icons) {
|
||||
print(yellow('''
|
||||
|
||||
------------------------------- IMPORTANT NOTICE -------------------------------
|
||||
Dynamic icon retrieval by name disables icon tree shaking. This means unused
|
||||
icons will not be automatically removed and thus make the overall app size
|
||||
larger. It is highly recommended to use this option only in combination with
|
||||
the "exclude" option, to remove styles which are not needed.
|
||||
You may need to pass --no-tree-shake-icons to the flutter build command for it
|
||||
to complete successfully.
|
||||
--------------------------------------------------------------------------------
|
||||
'''));
|
||||
|
||||
print(blue('Generating name to icon mapping'));
|
||||
|
||||
List<String> output = [
|
||||
'library font_awesome_flutter;',
|
||||
'',
|
||||
"import 'package:flutter/widgets.dart';",
|
||||
"import 'package:font_awesome_flutter/font_awesome_flutter.dart';",
|
||||
'',
|
||||
'// THIS FILE IS AUTOMATICALLY GENERATED!',
|
||||
'',
|
||||
'/// Utility function retrieve icons based on their css classes',
|
||||
'///',
|
||||
'/// [cssClasses] may contain other classes as well. This tool searches',
|
||||
'/// for the known font awesome classes (far, fas, fab, ...) and an icon',
|
||||
'/// name starting with `fa-`. Should multiple classes fulfill these',
|
||||
'/// requirements, the first occurrence is chosen.',
|
||||
'/// ',
|
||||
'/// Returns null if no icon matches.',
|
||||
'IconData? getIconFromCss(String cssClasses) {',
|
||||
' const Map<String, String> cssStyles = {',
|
||||
" 'far': 'regular', 'fas': 'solid', 'fab': 'brands',",
|
||||
" 'fad': 'duotone', 'fal': 'light', 'fat': 'thin',",
|
||||
' };',
|
||||
'',
|
||||
"var separatedCssClasses = cssClasses.split(' ');",
|
||||
'try {',
|
||||
' var style = separatedCssClasses.firstWhere((c) => cssStyles.containsKey(c));',
|
||||
' // fas -> solid',
|
||||
' style = cssStyles[style]!;',
|
||||
'',
|
||||
" var icon = separatedCssClasses.firstWhere((c) => c.startsWith('fa-'));",
|
||||
" icon = icon.replaceFirst('fa-', '');",
|
||||
'',
|
||||
" return faIconNameMapping['\$style \$icon'];",
|
||||
' } on StateError {',
|
||||
' return null;',
|
||||
' }',
|
||||
'}',
|
||||
'',
|
||||
'/// Icon name to icon mapping for font awesome icons',
|
||||
'///',
|
||||
'/// Keys are in the following format: "style iconName"',
|
||||
'const Map<String, IconData> faIconNameMapping = {',
|
||||
];
|
||||
|
||||
String iconName;
|
||||
for (var icon in icons) {
|
||||
for (var style in icon.styles) {
|
||||
iconName = normalizeIconName(icon.name, style, icon.styles.length);
|
||||
output.add("'$style ${icon.name}': FontAwesomeIcons.$iconName,");
|
||||
}
|
||||
}
|
||||
|
||||
output.add('};');
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the class with icon definitions and returns the output
|
||||
List<String> generateIconDefinitionClass(
|
||||
List<IconMetadata> metadata, Version version) {
|
||||
final List<String> output = [
|
||||
'library font_awesome_flutter;',
|
||||
'',
|
||||
"import 'package:flutter/widgets.dart';",
|
||||
"import 'package:font_awesome_flutter/src/icon_data.dart';",
|
||||
"export 'package:font_awesome_flutter/src/fa_icon.dart';",
|
||||
"export 'package:font_awesome_flutter/src/icon_data.dart';",
|
||||
];
|
||||
|
||||
output.addAll([
|
||||
'',
|
||||
'// THIS FILE IS AUTOMATICALLY GENERATED!',
|
||||
'',
|
||||
'/// Icons based on font awesome $version',
|
||||
'@staticIconProvider',
|
||||
'class FontAwesomeIcons {',
|
||||
]);
|
||||
|
||||
for (var icon in metadata) {
|
||||
for (String style in icon.styles) {
|
||||
output.add(generateIconDocumentation(icon, style));
|
||||
output.add(generateIconDefinition(icon, style));
|
||||
output.add(generateIconAliases(icon, style));
|
||||
}
|
||||
}
|
||||
|
||||
output.add('}');
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Builds the example icons
|
||||
List<String> generateExamplesListClass(List<IconMetadata> metadata) {
|
||||
final List<String> output = [
|
||||
"import 'package:font_awesome_flutter/font_awesome_flutter.dart';",
|
||||
"import 'package:font_awesome_flutter_example/example_icon.dart';",
|
||||
'',
|
||||
'// THIS FILE IS AUTOMATICALLY GENERATED!',
|
||||
'',
|
||||
'final icons = <ExampleIcon>[',
|
||||
];
|
||||
|
||||
for (var icon in metadata) {
|
||||
for (String style in icon.styles) {
|
||||
output.add(generateExampleIcon(icon, style));
|
||||
}
|
||||
}
|
||||
|
||||
output.add('];');
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/// Generates an icon for the example app. Used by [generateExamplesListClass]
|
||||
String generateExampleIcon(IconMetadata icon, String style) {
|
||||
var iconName = normalizeIconName(icon.name, style, icon.styles.length);
|
||||
|
||||
return "ExampleIcon(FontAwesomeIcons.$iconName, '$iconName'),";
|
||||
}
|
||||
|
||||
/// Generates the icon's doc comment. Used by [generateIconDefinitionClass]
|
||||
String generateIconDocumentation(IconMetadata icon, String style) {
|
||||
var doc = '/// ${style.sentenceCase} ${icon.label} icon\n'
|
||||
'///\n'
|
||||
'/// https://fontawesome.com/icons/${icon.name}?style=$style';
|
||||
|
||||
if (icon.searchTerms.isNotEmpty) {
|
||||
doc += '\n/// ${icon.searchTerms.join(", ")}';
|
||||
}
|
||||
|
||||
return doc;
|
||||
}
|
||||
|
||||
/// Generates the icon's constant. Used by [generateIconDefinitionClass]
|
||||
String generateIconDefinition(IconMetadata icon, String style) {
|
||||
var iconName = normalizeIconName(icon.name, style, icon.styles.length);
|
||||
|
||||
String iconDataSource = styleToDataSource(style);
|
||||
|
||||
return 'static const IconData $iconName = $iconDataSource(0x${icon.unicode});';
|
||||
}
|
||||
|
||||
/// Generates aliases which link to the original icon. Used by
|
||||
/// [generateIconDefinitionClass]
|
||||
String generateIconAliases(IconMetadata icon, String style) {
|
||||
var iconName = normalizeIconName(icon.name, style, icon.styles.length);
|
||||
final List<String> lines = [];
|
||||
|
||||
for (String alias in icon.aliases) {
|
||||
if (ignoredAliases.contains(alias)) continue;
|
||||
|
||||
var aliasName = normalizeIconName(alias, style, icon.styles.length);
|
||||
lines.add('/// Alias $alias for icon [$iconName]');
|
||||
lines.add('@Deprecated(\'Use "$iconName" instead.\')');
|
||||
lines.add('static const IconData $aliasName = $iconName;');
|
||||
}
|
||||
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/// Returns a normalized version of [iconName] which can be used as const name
|
||||
///
|
||||
/// [nameAdjustments] lists some icons which need special treatment to be valid
|
||||
/// const identifiers, as they cannot start with a number.
|
||||
/// The [style] name is automatically appended if necessary - deemed by the
|
||||
/// number of [styleCompetitors] (number of styles) for this icon.
|
||||
String normalizeIconName(String iconName, String style, int styleCompetitors) {
|
||||
iconName = nameAdjustments[iconName] ?? iconName;
|
||||
|
||||
if (styleCompetitors > 1 && style != "regular") {
|
||||
iconName = "${style}_$iconName";
|
||||
}
|
||||
|
||||
return iconName.camelCase;
|
||||
}
|
||||
|
||||
/// Utility function to generate the correct 'IconData' subclass for a [style]
|
||||
String styleToDataSource(String style) {
|
||||
return 'IconData${style[0].toUpperCase()}${style.substring(1)}';
|
||||
}
|
||||
|
||||
/// Gets the default branch from github's metadata
|
||||
///
|
||||
/// Font awesome no longer uses the master branch, but instead version specific
|
||||
/// ones, like 5.x and 6.x. Master is no longer updated. In the spirit of always
|
||||
/// using the latest version, this tool always selects the default branch.
|
||||
Future<String> getRepositoryDefaultBranch(String repositoryName) async {
|
||||
final tmpFile = File('fa-repo-metadata.tmp');
|
||||
await download('https://api.github.com/repos/$repositoryName', tmpFile);
|
||||
try {
|
||||
String rawGithubMetadata = await tmpFile.readAsString();
|
||||
Map<String, dynamic> githubMetadata = json.decode(rawGithubMetadata);
|
||||
return githubMetadata["default_branch"];
|
||||
} catch (_) {
|
||||
print(red('Error while getting font awesome\'s default branch. Aborting.'));
|
||||
} finally {
|
||||
tmpFile.delete();
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/// Prints a notice should the current font_awesome_flutter version not be the
|
||||
/// latest.
|
||||
Future printVersionNotice(String repositoryName) async {
|
||||
final tmpFile = File('faf-releases-metadata.tmp');
|
||||
|
||||
try {
|
||||
final packageVersion = pub.Version.parse(getPackageVersion());
|
||||
|
||||
print(blue('Using font_awesome_flutter version $packageVersion'));
|
||||
|
||||
await download(
|
||||
'https://api.github.com/repos/$repositoryName/releases', tmpFile);
|
||||
|
||||
String rawReleasesData = await tmpFile.readAsString();
|
||||
List releasesData = json.decode(rawReleasesData);
|
||||
List<pub.Version> releases = [];
|
||||
List<pub.Version> preReleases = [];
|
||||
for (final Map<String, dynamic> release in releasesData) {
|
||||
var releaseName = release["name"] as String;
|
||||
releaseName = releaseName.isEmpty ? release["tag_name"] : releaseName;
|
||||
// remove possible prefixes
|
||||
releaseName = releaseName
|
||||
.toLowerCase()
|
||||
.replaceAll('version', '')
|
||||
.replaceAll('v.', '')
|
||||
.replaceAll('v', '')
|
||||
.trim();
|
||||
final version = pub.Version.parse(releaseName);
|
||||
if (version.isPreRelease) {
|
||||
preReleases.add(version);
|
||||
} else {
|
||||
releases.add(version);
|
||||
}
|
||||
}
|
||||
|
||||
final primaryRelease = pub.Version.primary(releases);
|
||||
final primaryPreRelease = pub.Version.primary(preReleases);
|
||||
|
||||
if (primaryRelease > packageVersion) {
|
||||
print(red(
|
||||
'A new version ($primaryRelease) of font_awesome_flutter is available. Please update before reporting any errors. You can update via `git pull` or by downloading the source code from github. (https://github.com/$repositoryName)'));
|
||||
}
|
||||
if (primaryPreRelease > packageVersion &&
|
||||
primaryPreRelease > primaryRelease) {
|
||||
print(yellow(
|
||||
'A pre-release version ($primaryPreRelease) of font_awesome_flutter is available. Should you encounter any problems, have a look if it fixes them.'));
|
||||
}
|
||||
} catch (_) {
|
||||
print(red(
|
||||
'Error while getting font awesome flutter\'s version information. Could not determine whether you are using the latest version.'));
|
||||
} finally {
|
||||
tmpFile.delete();
|
||||
}
|
||||
// do not exit
|
||||
print('');
|
||||
}
|
||||
|
||||
/// Reads the [iconsJson] metadata and picks out relevant data
|
||||
///
|
||||
/// Relevant data includes search-terms, label, unicode, styles, changes and is
|
||||
/// saved to [metadata] as [IconMetadata].
|
||||
/// Changes versions are all put into the [versions] list to calculate the
|
||||
/// latest font awesome version.
|
||||
/// [excludedStyles], which can be set in the program arguments, are removed.
|
||||
/// Returns whether the dataset contains duotone icons.
|
||||
bool readAndPickMetadata(File iconsJson, List<IconMetadata> metadata,
|
||||
Set<String> styles, List<String> versions, List<String> excludedStyles) {
|
||||
var hasDuotoneIcons = false;
|
||||
|
||||
dynamic rawMetadata;
|
||||
try {
|
||||
final content = iconsJson.readAsStringSync();
|
||||
rawMetadata = json.decode(content);
|
||||
} catch (_) {
|
||||
print(
|
||||
'Error: Invalid icons.json. Please make sure you copied the correct file.');
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Map<String, dynamic> icon;
|
||||
for (var iconName in rawMetadata.keys) {
|
||||
icon = rawMetadata[iconName];
|
||||
|
||||
// Add all changes to the list
|
||||
for (var v in icon['changes'] as List) {
|
||||
versions.add(v);
|
||||
}
|
||||
|
||||
List<String> iconStyles = (icon['styles'] as List).cast<String>();
|
||||
|
||||
//TODO: Remove line once duotone support discontinuation notice is removed
|
||||
if (iconStyles.contains('duotone')) hasDuotoneIcons = true;
|
||||
|
||||
for (var excluded in excludedStyles) {
|
||||
iconStyles.remove(excluded);
|
||||
}
|
||||
|
||||
if (iconStyles.isEmpty) continue;
|
||||
|
||||
if (icon.containsKey('private') && icon['private']) continue;
|
||||
|
||||
styles.addAll(iconStyles);
|
||||
|
||||
final List searchTermsRaw = (icon['search']?['terms'] ?? []);
|
||||
final searchTerms = searchTermsRaw.map((e) => e.toString()).toList();
|
||||
|
||||
final List aliasesRaw = (icon['aliases']?['names'] ?? []);
|
||||
final aliases = aliasesRaw.map((e) => e.toString()).toList();
|
||||
|
||||
metadata.add(IconMetadata(
|
||||
iconName,
|
||||
icon['label'],
|
||||
icon['unicode'],
|
||||
searchTerms,
|
||||
iconStyles,
|
||||
aliases,
|
||||
));
|
||||
}
|
||||
|
||||
return hasDuotoneIcons;
|
||||
}
|
||||
|
||||
/// Calculates the highest version number found in the metadata
|
||||
///
|
||||
/// Expects a list of all versions listed in the metadata.
|
||||
/// See [readAndPickMetadata].
|
||||
Version calculateFontAwesomeVersion(List<String> versions) {
|
||||
final sortedVersions = versions.map((version) {
|
||||
try {
|
||||
return Version.parse(version);
|
||||
} on FormatException {
|
||||
return Version(0, 0, 0);
|
||||
}
|
||||
}).toList()
|
||||
..sort();
|
||||
|
||||
return sortedVersions.last;
|
||||
}
|
||||
|
||||
/// Downloads the content from [url] and saves it to [target]
|
||||
Future download(String url, File target) async {
|
||||
print('Downloading $url');
|
||||
final request = await HttpClient().getUrl(Uri.parse(url));
|
||||
final response = await request.close();
|
||||
return response.pipe(target.openWrite());
|
||||
}
|
||||
|
||||
/// Defines possible command line arguments for this program
|
||||
ArgParser setUpArgParser() {
|
||||
final argParser = ArgParser();
|
||||
|
||||
argParser.addFlag('help',
|
||||
abbr: 'h',
|
||||
defaultsTo: false,
|
||||
negatable: false,
|
||||
help: 'display program options and usage information');
|
||||
|
||||
argParser.addMultiOption('exclude',
|
||||
abbr: 'e',
|
||||
defaultsTo: [],
|
||||
allowed: ['brands', 'regular', 'solid', 'duotone', 'light', 'thin'],
|
||||
help: 'icon styles which are excluded by the generator');
|
||||
|
||||
argParser.addFlag('dynamic',
|
||||
abbr: 'd',
|
||||
defaultsTo: false,
|
||||
negatable: false,
|
||||
help: 'builds a map, which allows to dynamically retrieve icons by name');
|
||||
|
||||
return argParser;
|
||||
}
|
||||
|
||||
/// Displays the program help page. Accessible via the --help command line arg
|
||||
void displayHelp(ArgParser argParser) {
|
||||
var fileType = Platform.isWindows ? 'bat' : 'sh';
|
||||
print('''
|
||||
This script helps you to customize the font awesome flutter package to fit your
|
||||
individual needs. Please follow the "customizing font awesome flutter" guide on
|
||||
github.
|
||||
|
||||
By default, this tool acts as an updater. It retrieves the newest version of
|
||||
free font awesome icons from the web and generates all necessary files.
|
||||
If an icons.json exists within the lib/fonts folder, no update is performed and
|
||||
files in this folder are used for generation instead.
|
||||
To exclude styles from generation, pass the "exclude" option with a comma
|
||||
separated list of styles to ignore.
|
||||
|
||||
Usage:
|
||||
configurator.$fileType [options]
|
||||
|
||||
Options:''');
|
||||
print(argParser.usage);
|
||||
}
|
Reference in New Issue
Block a user