// Copyright 2014 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import 'dart:ui' show lerpDouble; import 'package:flutter/foundation.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; import 'material_state.dart'; import 'theme.dart'; import 'theme_data.dart'; /// Defines default property values for descendant [Switch] widgets. /// /// Descendant widgets obtain the current [SwitchThemeData] object using /// `SwitchTheme.of(context)`. Instances of [SwitchThemeData] can be customized /// with [SwitchThemeData.copyWith]. /// /// Typically a [SwitchThemeData] is specified as part of the overall [Theme] /// with [ThemeData.switchTheme]. /// /// All [SwitchThemeData] properties are `null` by default. When null, the /// [Switch] will use the values from [ThemeData] if they exist, otherwise it /// will provide its own defaults based on the overall [Theme]'s colorScheme. /// See the individual [Switch] properties for details. /// /// See also: /// /// * [ThemeData], which describes the overall theme information for the /// application. @immutable class SwitchThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.switchTheme]. const SwitchThemeData({ this.thumbColor, this.trackColor, this.materialTapTargetSize, this.mouseCursor, this.overlayColor, this.splashRadius, }); /// {@macro flutter.material.switch.thumbColor} /// /// If specified, overrides the default value of [Switch.thumbColor]. final MaterialStateProperty<Color?>? thumbColor; /// {@macro flutter.material.switch.trackColor} /// /// If specified, overrides the default value of [Switch.trackColor]. final MaterialStateProperty<Color?>? trackColor; /// {@macro flutter.material.switch.materialTapTargetSize} /// /// If specified, overrides the default value of /// [Switch.materialTapTargetSize]. final MaterialTapTargetSize? materialTapTargetSize; /// {@macro flutter.material.switch.mouseCursor} /// /// If specified, overrides the default value of [Switch.mouseCursor]. final MaterialStateProperty<MouseCursor?>? mouseCursor; /// {@macro flutter.material.switch.overlayColor} /// /// If specified, overrides the default value of [Switch.overlayColor]. final MaterialStateProperty<Color?>? overlayColor; /// {@macro flutter.material.switch.splashRadius} /// /// If specified, overrides the default value of [Switch.splashRadius]. final double? splashRadius; /// Creates a copy of this object but with the given fields replaced with the /// new values. SwitchThemeData copyWith({ MaterialStateProperty<Color?>? thumbColor, MaterialStateProperty<Color?>? trackColor, MaterialTapTargetSize? materialTapTargetSize, MaterialStateProperty<MouseCursor?>? mouseCursor, MaterialStateProperty<Color?>? overlayColor, double? splashRadius, }) { return SwitchThemeData( thumbColor: thumbColor ?? this.thumbColor, trackColor: trackColor ?? this.trackColor, materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize, mouseCursor: mouseCursor ?? this.mouseCursor, overlayColor: overlayColor ?? this.overlayColor, splashRadius: splashRadius ?? this.splashRadius, ); } /// Linearly interpolate between two [SwitchThemeData]s. /// /// {@macro dart.ui.shadow.lerp} static SwitchThemeData lerp(SwitchThemeData? a, SwitchThemeData? b, double t) { return SwitchThemeData( thumbColor: _lerpProperties<Color?>(a?.thumbColor, b?.thumbColor, t, Color.lerp), trackColor: _lerpProperties<Color?>(a?.trackColor, b?.trackColor, t, Color.lerp), materialTapTargetSize: t < 0.5 ? a?.materialTapTargetSize : b?.materialTapTargetSize, mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, overlayColor: _lerpProperties<Color?>(a?.overlayColor, b?.overlayColor, t, Color.lerp), splashRadius: lerpDouble(a?.splashRadius, b?.splashRadius, t), ); } @override int get hashCode { return hashValues( thumbColor, trackColor, materialTapTargetSize, mouseCursor, overlayColor, splashRadius, ); } @override bool operator ==(Object other) { if (identical(this, other)) return true; if (other.runtimeType != runtimeType) return false; return other is SwitchThemeData && other.thumbColor == thumbColor && other.trackColor == trackColor && other.materialTapTargetSize == materialTapTargetSize && other.mouseCursor == mouseCursor && other.overlayColor == overlayColor && other.splashRadius == splashRadius; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('thumbColor', thumbColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('trackColor', trackColor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null)); properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('overlayColor', overlayColor, defaultValue: null)); properties.add(DoubleProperty('splashRadius', splashRadius, defaultValue: null)); } static MaterialStateProperty<T>? _lerpProperties<T>( MaterialStateProperty<T>? a, MaterialStateProperty<T>? b, double t, T Function(T?, T?, double) lerpFunction, ) { // Avoid creating a _LerpProperties object for a common case. if (a == null && b == null) return null; return _LerpProperties<T>(a, b, t, lerpFunction); } } class _LerpProperties<T> implements MaterialStateProperty<T> { const _LerpProperties(this.a, this.b, this.t, this.lerpFunction); final MaterialStateProperty<T>? a; final MaterialStateProperty<T>? b; final double t; final T Function(T?, T?, double) lerpFunction; @override T resolve(Set<MaterialState> states) { final T? resolvedA = a?.resolve(states); final T? resolvedB = b?.resolve(states); return lerpFunction(resolvedA, resolvedB, t); } } /// Applies a switch theme to descendant [Switch] widgets. /// /// Descendant widgets obtain the current theme's [SwitchTheme] object using /// [SwitchTheme.of]. When a widget uses [SwitchTheme.of], it is automatically /// rebuilt if the theme later changes. /// /// A switch theme can be specified as part of the overall Material theme using /// [ThemeData.switchTheme]. /// /// See also: /// /// * [SwitchThemeData], which describes the actual configuration of a switch /// theme. class SwitchTheme extends InheritedWidget { /// Constructs a switch theme that configures all descendant [Switch] widgets. const SwitchTheme({ Key? key, required this.data, required Widget child, }) : super(key: key, child: child); /// The properties used for all descendant [Switch] widgets. final SwitchThemeData data; /// Returns the configuration [data] from the closest [SwitchTheme] ancestor. /// If there is no ancestor, it returns [ThemeData.switchTheme]. /// /// Typical usage is as follows: /// /// ```dart /// SwitchThemeData theme = SwitchTheme.of(context); /// ``` static SwitchThemeData of(BuildContext context) { final SwitchTheme? switchTheme = context.dependOnInheritedWidgetOfExactType<SwitchTheme>(); return switchTheme?.data ?? Theme.of(context).switchTheme; } @override bool updateShouldNotify(SwitchTheme oldWidget) => data != oldWidget.data; }