mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Adaptive icons (#69119)
* refactor update_icons * fix trailing space * address feedback * add platform adaptive icons * fix merge conflict * Update dartdoc * Address feedback * Specify types * Add tests * fix indentation * Remove trailing space * Remove isCupertino static bool
This commit is contained in:
parent
c1042314a9
commit
2f17d4e017
@ -20,8 +20,20 @@ const String _defaultNewCodepointsPath = 'codepoints';
|
||||
const String _defaultOldCodepointsPath = 'bin/cache/artifacts/material_fonts/codepoints';
|
||||
const String _defaultIconsPath = 'packages/flutter/lib/src/material/icons.dart';
|
||||
|
||||
const String _beginGeneratedMark = '// BEGIN GENERATED';
|
||||
const String _endGeneratedMark = '// END GENERATED';
|
||||
const String _beginGeneratedMark = '// BEGIN GENERATED ICONS';
|
||||
const String _endGeneratedMark = '// END GENERATED ICONS';
|
||||
const String _beginPlatformAdaptiveGeneratedMark = '// BEGIN GENERATED PLATFORM ADAPTIVE ICONS';
|
||||
const String _endPlatformAdaptiveGeneratedMark = '// END GENERATED PLATFORM ADAPTIVE ICONS';
|
||||
|
||||
const Map<String, List<String>> _platformAdaptiveIdentifiers = <String, List<String>>{
|
||||
// Mapping of Flutter IDs to an Android/agnostic ID and an iOS ID.
|
||||
// Flutter IDs can be anything, but should be chosen to be agnostic.
|
||||
'arrow_back': <String>['arrow_back', 'arrow_back_ios'],
|
||||
'arrow_forward': <String>['arrow_forward', 'arrow_forward_ios'],
|
||||
'flip_camera': <String>['flip_camera_android', 'flip_camera_ios'],
|
||||
'more': <String>['more_vert', 'more_horiz'],
|
||||
'share': <String>['share', 'ios_share'],
|
||||
};
|
||||
|
||||
const Map<String, String> _identifierRewrites = <String, String>{
|
||||
'360': 'threesixty',
|
||||
@ -231,20 +243,54 @@ Map<String, String> stringToTokenPairMap(String codepointData) {
|
||||
|
||||
// Do not make this method private as it is used by g3 roll.
|
||||
String regenerateIconsFile(String iconData, Map<String, String> tokenPairMap) {
|
||||
final Iterable<_Icon> newIcons = tokenPairMap.entries.map((MapEntry<String, String> entry) => _Icon(entry));
|
||||
final StringBuffer buf = StringBuffer();
|
||||
bool generating = false;
|
||||
|
||||
for (final String line in LineSplitter.split(iconData)) {
|
||||
if (!generating) {
|
||||
buf.writeln(line);
|
||||
}
|
||||
if (line.contains(_beginGeneratedMark)) {
|
||||
|
||||
// Generate for _PlatformAdaptiveIcons
|
||||
if (line.contains(_beginPlatformAdaptiveGeneratedMark)) {
|
||||
generating = true;
|
||||
|
||||
final String iconDeclarationsString = <String>[
|
||||
for (MapEntry<String, String> entry in tokenPairMap.entries)
|
||||
_Icon(entry).fullDeclaration
|
||||
].join();
|
||||
final List<String> platformAdaptiveDeclarations = <String>[];
|
||||
_platformAdaptiveIdentifiers.forEach((String flutterId, List<String> ids) {
|
||||
// Automatically finds and generates styled icon declarations.
|
||||
for (final IconStyle iconStyle in IconStyle.values) {
|
||||
final String style = iconStyle.idSuffix();
|
||||
try {
|
||||
final _Icon agnosticIcon = newIcons.firstWhere(
|
||||
(_Icon icon) => icon.id == '${ids[0]}$style',
|
||||
orElse: () => throw ids[0]);
|
||||
final _Icon iOSIcon = newIcons.firstWhere(
|
||||
(_Icon icon) => icon.id == '${ids[1]}$style',
|
||||
orElse: () => throw ids[1]);
|
||||
|
||||
platformAdaptiveDeclarations.add(_Icon.platformAdaptiveDeclaration('$flutterId$style', agnosticIcon, iOSIcon));
|
||||
} catch (e) {
|
||||
if (iconStyle == IconStyle.regular) {
|
||||
stderr.writeln("Error while generating platformAdaptiveDeclarations: Icon '$e' not found.");
|
||||
exit(1);
|
||||
} else {
|
||||
// Ignore errors for styled icons since some don't exist.
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
buf.write(platformAdaptiveDeclarations.join());
|
||||
} else if (line.contains(_endPlatformAdaptiveGeneratedMark)) {
|
||||
generating = false;
|
||||
buf.writeln(line);
|
||||
}
|
||||
|
||||
// Generate for Icons
|
||||
if (line.contains(_beginGeneratedMark)) {
|
||||
generating = true;
|
||||
final String iconDeclarationsString = newIcons.map((_Icon icon) => icon.fullDeclaration).join('');
|
||||
buf.write(iconDeclarationsString);
|
||||
} else if (line.contains(_endGeneratedMark)) {
|
||||
generating = false;
|
||||
@ -275,9 +321,9 @@ enum IconStyle {
|
||||
sharp,
|
||||
}
|
||||
|
||||
extension IconStyleSuffix on IconStyle {
|
||||
extension IconStyleExtension on IconStyle {
|
||||
// The suffix for the 'material-icons' HTML class.
|
||||
String suffix() {
|
||||
String htmlSuffix() {
|
||||
switch (this) {
|
||||
case IconStyle.outlined: return '-outlined';
|
||||
case IconStyle.rounded: return '-round';
|
||||
@ -285,6 +331,17 @@ extension IconStyleSuffix on IconStyle {
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
|
||||
// The suffix for icon ids.
|
||||
String idSuffix() {
|
||||
switch (this) {
|
||||
case IconStyle.outlined:
|
||||
case IconStyle.rounded:
|
||||
case IconStyle.sharp:
|
||||
return '_' + toString().split('.').last;
|
||||
default: return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class _Icon {
|
||||
@ -332,12 +389,25 @@ class _Icon {
|
||||
String get name => id.replaceAll('_', ' ');
|
||||
|
||||
String get dartDoc =>
|
||||
'/// <i class="material-icons${style.suffix()} md-36">$shortId</i> — material icon named "$name".';
|
||||
'<i class="material-icons${style.htmlSuffix()} md-36">$shortId</i> — material icon named "$name"';
|
||||
|
||||
String get declaration =>
|
||||
"static const IconData $flutterId = IconData(0x$hexCodepoint, fontFamily: 'MaterialIcons'$mirroredInRTL);";
|
||||
|
||||
String get fullDeclaration => '''\n $dartDoc\n $declaration\n''';
|
||||
String get fullDeclaration => '''
|
||||
|
||||
/// $dartDoc.
|
||||
$declaration
|
||||
''';
|
||||
|
||||
static String platformAdaptiveDeclaration(String flutterId, _Icon agnosticIcon, _Icon iOSIcon) => '''
|
||||
|
||||
/// Platform-adaptive icon for ${agnosticIcon.dartDoc} and ${iOSIcon.dartDoc}.;
|
||||
IconData get $flutterId => !_isCupertino() ? Icons.${agnosticIcon.flutterId} : Icons.${iOSIcon.flutterId};
|
||||
''';
|
||||
|
||||
@override
|
||||
String toString() => id;
|
||||
}
|
||||
|
||||
// Replace the old codepoints file with the new.
|
||||
|
||||
@ -2,8 +2,81 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:flutter/foundation.dart' show defaultTargetPlatform;
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
// ignore_for_file: non_constant_identifier_names
|
||||
class _PlatformAdaptiveIcons {
|
||||
static bool _isCupertino() {
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
case TargetPlatform.fuchsia:
|
||||
case TargetPlatform.linux:
|
||||
case TargetPlatform.windows:
|
||||
return false;
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.macOS:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Generated code: do not hand-edit.
|
||||
// See https://github.com/flutter/flutter/wiki/Updating-Material-Design-Fonts
|
||||
// BEGIN GENERATED PLATFORM ADAPTIVE ICONS
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons md-36">arrow_back</i> — material icon named "arrow back" and <i class="material-icons md-36">arrow_back_ios</i> — material icon named "arrow back ios".;
|
||||
IconData get arrow_back => !_isCupertino() ? Icons.arrow_back : Icons.arrow_back_ios;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-outlined md-36">arrow_back</i> — material icon named "arrow back outlined" and <i class="material-icons-outlined md-36">arrow_back_ios</i> — material icon named "arrow back ios outlined".;
|
||||
IconData get arrow_back_outlined => !_isCupertino() ? Icons.arrow_back_outlined : Icons.arrow_back_ios_outlined;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-round md-36">arrow_back</i> — material icon named "arrow back rounded" and <i class="material-icons-round md-36">arrow_back_ios</i> — material icon named "arrow back ios rounded".;
|
||||
IconData get arrow_back_rounded => !_isCupertino() ? Icons.arrow_back_rounded : Icons.arrow_back_ios_rounded;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-sharp md-36">arrow_back</i> — material icon named "arrow back sharp" and <i class="material-icons-sharp md-36">arrow_back_ios</i> — material icon named "arrow back ios sharp".;
|
||||
IconData get arrow_back_sharp => !_isCupertino() ? Icons.arrow_back_sharp : Icons.arrow_back_ios_sharp;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons md-36">arrow_forward</i> — material icon named "arrow forward" and <i class="material-icons md-36">arrow_forward_ios</i> — material icon named "arrow forward ios".;
|
||||
IconData get arrow_forward => !_isCupertino() ? Icons.arrow_forward : Icons.arrow_forward_ios;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-outlined md-36">arrow_forward</i> — material icon named "arrow forward outlined" and <i class="material-icons-outlined md-36">arrow_forward_ios</i> — material icon named "arrow forward ios outlined".;
|
||||
IconData get arrow_forward_outlined => !_isCupertino() ? Icons.arrow_forward_outlined : Icons.arrow_forward_ios_outlined;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-round md-36">arrow_forward</i> — material icon named "arrow forward rounded" and <i class="material-icons-round md-36">arrow_forward_ios</i> — material icon named "arrow forward ios rounded".;
|
||||
IconData get arrow_forward_rounded => !_isCupertino() ? Icons.arrow_forward_rounded : Icons.arrow_forward_ios_rounded;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-sharp md-36">arrow_forward</i> — material icon named "arrow forward sharp" and <i class="material-icons-sharp md-36">arrow_forward_ios</i> — material icon named "arrow forward ios sharp".;
|
||||
IconData get arrow_forward_sharp => !_isCupertino() ? Icons.arrow_forward_sharp : Icons.arrow_forward_ios_sharp;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons md-36">flip_camera_android</i> — material icon named "flip camera android" and <i class="material-icons md-36">flip_camera_ios</i> — material icon named "flip camera ios".;
|
||||
IconData get flip_camera => !_isCupertino() ? Icons.flip_camera_android : Icons.flip_camera_ios;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-outlined md-36">flip_camera_android</i> — material icon named "flip camera android outlined" and <i class="material-icons-outlined md-36">flip_camera_ios</i> — material icon named "flip camera ios outlined".;
|
||||
IconData get flip_camera_outlined => !_isCupertino() ? Icons.flip_camera_android_outlined : Icons.flip_camera_ios_outlined;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-round md-36">flip_camera_android</i> — material icon named "flip camera android rounded" and <i class="material-icons-round md-36">flip_camera_ios</i> — material icon named "flip camera ios rounded".;
|
||||
IconData get flip_camera_rounded => !_isCupertino() ? Icons.flip_camera_android_rounded : Icons.flip_camera_ios_rounded;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-sharp md-36">flip_camera_android</i> — material icon named "flip camera android sharp" and <i class="material-icons-sharp md-36">flip_camera_ios</i> — material icon named "flip camera ios sharp".;
|
||||
IconData get flip_camera_sharp => !_isCupertino() ? Icons.flip_camera_android_sharp : Icons.flip_camera_ios_sharp;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons md-36">more_vert</i> — material icon named "more vert" and <i class="material-icons md-36">more_horiz</i> — material icon named "more horiz".;
|
||||
IconData get more => !_isCupertino() ? Icons.more_vert : Icons.more_horiz;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-outlined md-36">more_vert</i> — material icon named "more vert outlined" and <i class="material-icons-outlined md-36">more_horiz</i> — material icon named "more horiz outlined".;
|
||||
IconData get more_outlined => !_isCupertino() ? Icons.more_vert_outlined : Icons.more_horiz_outlined;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-round md-36">more_vert</i> — material icon named "more vert rounded" and <i class="material-icons-round md-36">more_horiz</i> — material icon named "more horiz rounded".;
|
||||
IconData get more_rounded => !_isCupertino() ? Icons.more_vert_rounded : Icons.more_horiz_rounded;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons-sharp md-36">more_vert</i> — material icon named "more vert sharp" and <i class="material-icons-sharp md-36">more_horiz</i> — material icon named "more horiz sharp".;
|
||||
IconData get more_sharp => !_isCupertino() ? Icons.more_vert_sharp : Icons.more_horiz_sharp;
|
||||
|
||||
/// Platform-adaptive icon for <i class="material-icons md-36">share</i> — material icon named "share" and <i class="material-icons md-36">ios_share</i> — material icon named "ios share".;
|
||||
IconData get share => !_isCupertino() ? Icons.share : Icons.ios_share;
|
||||
// END GENERATED PLATFORM ADAPTIVE ICONS
|
||||
}
|
||||
|
||||
/// Identifiers for the supported material design icons.
|
||||
///
|
||||
/// Use with the [Icon] class to show specific icons.
|
||||
@ -64,9 +137,35 @@ class Icons {
|
||||
// ignore: unused_element
|
||||
Icons._();
|
||||
|
||||
/// A set of platform-adaptive material design icons.
|
||||
///
|
||||
/// Provides a convenient way to show a certain set of platform-appropriate
|
||||
/// icons on Apple platforms.
|
||||
///
|
||||
/// Use with the [Icon] class to show specific icons.
|
||||
///
|
||||
/// {@tool snippet}
|
||||
/// This example shows how to create a share icon that uses the material icon
|
||||
/// named "share" on non-Apple platforms, and the icon named "ios share" on
|
||||
/// Apple platforms.
|
||||
///
|
||||
/// ```dart
|
||||
/// Icon(
|
||||
/// Icons.adaptive.share,
|
||||
/// )
|
||||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Icon]
|
||||
/// * [IconButton]
|
||||
/// * <https://design.google.com/icons/>
|
||||
static _PlatformAdaptiveIcons get adaptive => _PlatformAdaptiveIcons();
|
||||
|
||||
// Generated code: do not hand-edit.
|
||||
// See https://github.com/flutter/flutter/wiki/Updating-Material-Design-Fonts
|
||||
// BEGIN GENERATED
|
||||
// BEGIN GENERATED ICONS
|
||||
|
||||
/// <i class="material-icons md-36">10k</i> — material icon named "10k".
|
||||
static const IconData ten_k = IconData(0xe52a, fontFamily: 'MaterialIcons');
|
||||
@ -17029,5 +17128,5 @@ class Icons {
|
||||
|
||||
/// <i class="material-icons-sharp md-36">zoom_out</i> — material icon named "zoom out sharp".
|
||||
static const IconData zoom_out_sharp = IconData(0xf02d, fontFamily: 'MaterialIcons');
|
||||
// END GENERATED
|
||||
// END GENERATED ICONS
|
||||
}
|
||||
|
||||
@ -16,4 +16,29 @@ void main() {
|
||||
expect(Icons.clear.fontFamily, 'MaterialIcons');
|
||||
expect(Icons.search.fontFamily, 'MaterialIcons');
|
||||
});
|
||||
|
||||
testWidgets('Adaptive icons are correct on cupertino platforms',
|
||||
(WidgetTester tester) async {
|
||||
expect(Icons.adaptive.arrow_back, Icons.arrow_back_ios);
|
||||
expect(Icons.adaptive.arrow_back_outlined, Icons.arrow_back_ios_outlined);
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{
|
||||
TargetPlatform.iOS,
|
||||
TargetPlatform.macOS,
|
||||
}),
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'Adaptive icons are correct on non-cupertino platforms',
|
||||
(WidgetTester tester) async {
|
||||
expect(Icons.adaptive.arrow_back, Icons.arrow_back);
|
||||
expect(Icons.adaptive.arrow_back_outlined, Icons.arrow_back_outlined);
|
||||
},
|
||||
variant: const TargetPlatformVariant(<TargetPlatform>{
|
||||
TargetPlatform.android,
|
||||
TargetPlatform.fuchsia,
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.linux,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user