diff --git a/AUTHORS b/AUTHORS index ec81732a276..3742c2564ea 100644 --- a/AUTHORS +++ b/AUTHORS @@ -134,3 +134,4 @@ Mohammed Chahboun Abdessalem Mohellebi Jin Jeongsu Mairon Slusarz +Ricardo Dalarme diff --git a/packages/flutter/lib/src/cupertino/text_selection.dart b/packages/flutter/lib/src/cupertino/text_selection.dart index c88c776d240..9763bee98af 100644 --- a/packages/flutter/lib/src/cupertino/text_selection.dart +++ b/packages/flutter/lib/src/cupertino/text_selection.dart @@ -122,7 +122,9 @@ class CupertinoTextSelectionControls extends TextSelectionControls { final Widget handle; final Widget customPaint = CustomPaint( - painter: _CupertinoTextSelectionHandlePainter(CupertinoTheme.of(context).primaryColor), + painter: _CupertinoTextSelectionHandlePainter( + CupertinoTheme.of(context).selectionHandleColor, + ), ); // [buildHandle]'s widget is positioned at the selection cursor's bottom diff --git a/packages/flutter/lib/src/cupertino/theme.dart b/packages/flutter/lib/src/cupertino/theme.dart index db0a330abc4..6e359c2e8d1 100644 --- a/packages/flutter/lib/src/cupertino/theme.dart +++ b/packages/flutter/lib/src/cupertino/theme.dart @@ -29,6 +29,7 @@ const _CupertinoThemeDefaults _kDefaultTheme = _CupertinoThemeDefaults( // Values extracted from navigation bar. For toolbar or tabbar the dark color is 0xF0161616. ), CupertinoColors.systemBackground, + CupertinoColors.systemBlue, false, _CupertinoTextThemeDefaults(CupertinoColors.label, CupertinoColors.inactiveGray), ); @@ -179,6 +180,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, }) : this.raw( brightness, @@ -187,6 +189,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme, barBackgroundColor, scaffoldBackgroundColor, + selectionHandleColor, applyThemeToAll, ); @@ -202,6 +205,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, ) : this._rawWithDefaults( brightness, @@ -210,6 +214,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme, barBackgroundColor, scaffoldBackgroundColor, + selectionHandleColor, applyThemeToAll, _kDefaultTheme, ); @@ -221,6 +226,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, this._defaults, ) : super( @@ -230,6 +236,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme: textTheme, barBackgroundColor: barBackgroundColor, scaffoldBackgroundColor: scaffoldBackgroundColor, + selectionHandleColor: selectionHandleColor, applyThemeToAll: applyThemeToAll, ); @@ -255,6 +262,9 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable Color get scaffoldBackgroundColor => super.scaffoldBackgroundColor ?? _defaults.scaffoldBackgroundColor; + @override + Color get selectionHandleColor => super.selectionHandleColor ?? _defaults.selectionHandleColor; + @override bool get applyThemeToAll => super.applyThemeToAll ?? _defaults.applyThemeToAll; @@ -267,6 +277,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme: super.textTheme, barBackgroundColor: super.barBackgroundColor, scaffoldBackgroundColor: super.scaffoldBackgroundColor, + selectionHandleColor: super.selectionHandleColor, applyThemeToAll: super.applyThemeToAll, ); } @@ -282,6 +293,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable super.textTheme?.resolveFrom(context), convertColor(super.barBackgroundColor), convertColor(super.scaffoldBackgroundColor), + convertColor(super.selectionHandleColor), applyThemeToAll, _defaults.resolveFrom(context, super.textTheme == null), ); @@ -295,6 +307,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, }) { return CupertinoThemeData._rawWithDefaults( @@ -304,6 +317,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme ?? super.textTheme, barBackgroundColor ?? super.barBackgroundColor, scaffoldBackgroundColor ?? super.scaffoldBackgroundColor, + selectionHandleColor ?? super.selectionHandleColor, applyThemeToAll ?? super.applyThemeToAll, _defaults, ); @@ -342,6 +356,13 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable defaultValue: defaultData.scaffoldBackgroundColor, ), ); + properties.add( + createCupertinoColorProperty( + 'selectionHandleColor', + selectionHandleColor, + defaultValue: defaultData.selectionHandleColor, + ), + ); properties.add( DiagnosticsProperty( 'applyThemeToAll', @@ -367,6 +388,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable other.textTheme == textTheme && other.barBackgroundColor == barBackgroundColor && other.scaffoldBackgroundColor == scaffoldBackgroundColor && + other.selectionHandleColor == selectionHandleColor && other.applyThemeToAll == applyThemeToAll; } @@ -378,6 +400,7 @@ class CupertinoThemeData extends NoDefaultCupertinoThemeData with Diagnosticable textTheme, barBackgroundColor, scaffoldBackgroundColor, + selectionHandleColor, applyThemeToAll, ); } @@ -406,6 +429,7 @@ class NoDefaultCupertinoThemeData { this.textTheme, this.barBackgroundColor, this.scaffoldBackgroundColor, + this.selectionHandleColor, this.applyThemeToAll, }); @@ -474,6 +498,11 @@ class NoDefaultCupertinoThemeData { /// Defaults to [CupertinoColors.systemBackground]. final Color? scaffoldBackgroundColor; + /// The color of the selection handles on the text field. + /// + /// Defaults to [CupertinoColors.systemBlue]. + final Color? selectionHandleColor; + /// Flag to apply this theme to all descendant Cupertino widgets. /// /// Certain Cupertino widgets previously didn't use theming, matching past @@ -513,6 +542,7 @@ class NoDefaultCupertinoThemeData { textTheme: textTheme?.resolveFrom(context), barBackgroundColor: convertColor(barBackgroundColor), scaffoldBackgroundColor: convertColor(scaffoldBackgroundColor), + selectionHandleColor: convertColor(selectionHandleColor), applyThemeToAll: applyThemeToAll, ); } @@ -530,6 +560,7 @@ class NoDefaultCupertinoThemeData { CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, }) { return NoDefaultCupertinoThemeData( @@ -539,6 +570,7 @@ class NoDefaultCupertinoThemeData { textTheme: textTheme ?? this.textTheme, barBackgroundColor: barBackgroundColor ?? this.barBackgroundColor, scaffoldBackgroundColor: scaffoldBackgroundColor ?? this.scaffoldBackgroundColor, + selectionHandleColor: selectionHandleColor ?? this.selectionHandleColor, applyThemeToAll: applyThemeToAll ?? this.applyThemeToAll, ); } @@ -581,6 +613,7 @@ class _CupertinoThemeDefaults { this.primaryContrastingColor, this.barBackgroundColor, this.scaffoldBackgroundColor, + this.selectionHandleColor, this.applyThemeToAll, this.textThemeDefaults, ); @@ -590,6 +623,7 @@ class _CupertinoThemeDefaults { final Color primaryContrastingColor; final Color barBackgroundColor; final Color scaffoldBackgroundColor; + final Color selectionHandleColor; final bool applyThemeToAll; final _CupertinoTextThemeDefaults textThemeDefaults; @@ -602,6 +636,7 @@ class _CupertinoThemeDefaults { convertColor(primaryContrastingColor), convertColor(barBackgroundColor), convertColor(scaffoldBackgroundColor), + convertColor(selectionHandleColor), applyThemeToAll, resolveTextTheme ? textThemeDefaults.resolveFrom(context) : textThemeDefaults, ); diff --git a/packages/flutter/lib/src/material/text_selection_theme.dart b/packages/flutter/lib/src/material/text_selection_theme.dart index 855a5f759b0..9408b5f7f88 100644 --- a/packages/flutter/lib/src/material/text_selection_theme.dart +++ b/packages/flutter/lib/src/material/text_selection_theme.dart @@ -53,8 +53,8 @@ class TextSelectionThemeData with Diagnosticable { /// /// On iOS [TextField] and [SelectableText] cannot access [selectionHandleColor]. /// To set the [selectionHandleColor] on iOS, you can change the - /// [CupertinoThemeData.primaryColor] by wrapping the subtree containing - /// your [TextField] or [SelectableText] with a [CupertinoTheme]. + /// [CupertinoThemeData.selectionHandleColor] by wrapping the subtree + /// containing your [TextField] or [SelectableText] with a [CupertinoTheme]. final Color? selectionHandleColor; /// Creates a copy of this object with the given fields replaced with the diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart index bedd45b489d..f01315b5ab2 100644 --- a/packages/flutter/lib/src/material/theme_data.dart +++ b/packages/flutter/lib/src/material/theme_data.dart @@ -2925,6 +2925,8 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData { _cupertinoOverrideTheme.textTheme, _cupertinoOverrideTheme.barBackgroundColor, _cupertinoOverrideTheme.scaffoldBackgroundColor, + _cupertinoOverrideTheme.selectionHandleColor ?? + _materialTheme.textSelectionTheme.selectionHandleColor, _cupertinoOverrideTheme.applyThemeToAll, ); @@ -2964,6 +2966,7 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData { CupertinoTextThemeData? textTheme, Color? barBackgroundColor, Color? scaffoldBackgroundColor, + Color? selectionHandleColor, bool? applyThemeToAll, }) { return MaterialBasedCupertinoThemeData._( @@ -2975,6 +2978,7 @@ class MaterialBasedCupertinoThemeData extends CupertinoThemeData { textTheme: textTheme, barBackgroundColor: barBackgroundColor, scaffoldBackgroundColor: scaffoldBackgroundColor, + selectionHandleColor: selectionHandleColor, applyThemeToAll: applyThemeToAll, ), ); diff --git a/packages/flutter/test/cupertino/text_field_test.dart b/packages/flutter/test/cupertino/text_field_test.dart index 8db15f582f0..aee384c931a 100644 --- a/packages/flutter/test/cupertino/text_field_test.dart +++ b/packages/flutter/test/cupertino/text_field_test.dart @@ -674,10 +674,10 @@ void main() { await tester.pumpWidget( CupertinoApp( - theme: const CupertinoThemeData(primaryColor: Colors.red), + theme: const CupertinoThemeData(selectionHandleColor: Colors.red), home: Center( child: CupertinoTheme( - data: const CupertinoThemeData(primaryColor: expectedSelectionHandleColor), + data: const CupertinoThemeData(selectionHandleColor: expectedSelectionHandleColor), child: CupertinoTextField(controller: controller), ), ), diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart index 3cc77230f98..0b45a9bd6f8 100644 --- a/packages/flutter/test/cupertino/text_selection_test.dart +++ b/packages/flutter/test/cupertino/text_selection_test.dart @@ -149,11 +149,45 @@ void main() { }); group('cupertino handles', () { + testWidgets('draws custom handle correctly', (WidgetTester tester) async { + await tester.pumpWidget( + RepaintBoundary( + child: CupertinoTheme( + data: const CupertinoThemeData(selectionHandleColor: Color(0xFF9C27B0)), + child: Builder( + builder: (BuildContext context) { + return Container( + color: CupertinoColors.white, + height: 800, + width: 800, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 250), + child: FittedBox( + child: cupertinoTextSelectionControls.buildHandle( + context, + TextSelectionHandleType.right, + 10.0, + ), + ), + ), + ); + }, + ), + ), + ), + ); + + await expectLater( + find.byType(RepaintBoundary), + matchesGoldenFile('text_selection.handle.custom.png'), + ); + }); + testWidgets('draws transparent handle correctly', (WidgetTester tester) async { await tester.pumpWidget( RepaintBoundary( child: CupertinoTheme( - data: const CupertinoThemeData(primaryColor: Color(0x550000AA)), + data: const CupertinoThemeData(selectionHandleColor: Color(0x550000AA)), child: Builder( builder: (BuildContext context) { return Container( diff --git a/packages/flutter/test/cupertino/theme_test.dart b/packages/flutter/test/cupertino/theme_test.dart index 78e469276d5..f3ba9e1a375 100644 --- a/packages/flutter/test/cupertino/theme_test.dart +++ b/packages/flutter/test/cupertino/theme_test.dart @@ -193,6 +193,7 @@ void main() { 'navActionTextStyle', 'pickerTextStyle', 'dateTimePickerTextStyle', + 'selectionHandleColor', }), isTrue, ); @@ -272,6 +273,7 @@ void main() { colorMatches(theme.primaryContrastingColor, CupertinoColors.white); colorMatches(theme.barBackgroundColor, barBackgroundColor); colorMatches(theme.scaffoldBackgroundColor, CupertinoColors.systemBackground); + colorMatches(theme.selectionHandleColor, CupertinoColors.systemBlue); colorMatches(theme.textTheme.textStyle.color, CupertinoColors.label); colorMatches(theme.textTheme.actionTextStyle.color, primaryColor); colorMatches(theme.textTheme.tabLabelTextStyle.color, CupertinoColors.inactiveGray);