// 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 'theme.dart'; // Examples can assume: // late BuildContext context; /// Defines the configuration of the search views created by the [SearchAnchor] /// widget. /// /// Descendant widgets obtain the current [SearchViewThemeData] object using /// `SearchViewTheme.of(context)`. /// /// Typically, a [SearchViewThemeData] is specified as part of the overall [Theme] /// with [ThemeData.searchViewTheme]. Otherwise, [SearchViewTheme] can be used /// to configure its own widget subtree. /// /// All [SearchViewThemeData] properties are `null` by default. If any of these /// properties are null, the search view will provide its own defaults. /// /// See also: /// /// * [ThemeData], which describes the overall theme for the application. /// * [SearchBarThemeData], which describes the theme for the search bar itself in a /// [SearchBar] widget. /// * [SearchAnchor], which is used to open a search view route. @immutable class SearchViewThemeData with Diagnosticable { /// Creates a theme that can be used for [ThemeData.searchViewTheme]. const SearchViewThemeData({ this.backgroundColor, this.elevation, this.surfaceTintColor, this.constraints, this.side, this.shape, this.headerTextStyle, this.headerHintStyle, this.dividerColor, }); /// Overrides the default value of the [SearchAnchor.viewBackgroundColor]. final Color? backgroundColor; /// Overrides the default value of the [SearchAnchor.viewElevation]. final double? elevation; /// Overrides the default value of the [SearchAnchor.viewSurfaceTintColor]. final Color? surfaceTintColor; /// Overrides the default value of the [SearchAnchor.viewSide]. final BorderSide? side; /// Overrides the default value of the [SearchAnchor.viewShape]. final OutlinedBorder? shape; /// Overrides the default value for [SearchAnchor.headerTextStyle]. final TextStyle? headerTextStyle; /// Overrides the default value for [SearchAnchor.headerHintStyle]. final TextStyle? headerHintStyle; /// Overrides the value of size constraints for [SearchAnchor.viewConstraints]. final BoxConstraints? constraints; /// Overrides the value of the divider color for [SearchAnchor.dividerColor]. final Color? dividerColor; /// Creates a copy of this object but with the given fields replaced with the /// new values. SearchViewThemeData copyWith({ Color? backgroundColor, double? elevation, Color? surfaceTintColor, BorderSide? side, OutlinedBorder? shape, TextStyle? headerTextStyle, TextStyle? headerHintStyle, BoxConstraints? constraints, Color? dividerColor, }) { return SearchViewThemeData( backgroundColor: backgroundColor ?? this.backgroundColor, elevation: elevation ?? this.elevation, surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, side: side ?? this.side, shape: shape ?? this.shape, headerTextStyle: headerTextStyle ?? this.headerTextStyle, headerHintStyle: headerHintStyle ?? this.headerHintStyle, constraints: constraints ?? this.constraints, dividerColor: dividerColor ?? this.dividerColor, ); } /// Linearly interpolate between two [SearchViewThemeData]s. static SearchViewThemeData? lerp(SearchViewThemeData? a, SearchViewThemeData? b, double t) { if (identical(a, b)) { return a; } return SearchViewThemeData( backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), side: _lerpSides(a?.side, b?.side, t), shape: OutlinedBorder.lerp(a?.shape, b?.shape, t), headerTextStyle: TextStyle.lerp(a?.headerTextStyle, b?.headerTextStyle, t), headerHintStyle: TextStyle.lerp(a?.headerTextStyle, b?.headerTextStyle, t), constraints: BoxConstraints.lerp(a?.constraints, b?.constraints, t), dividerColor: Color.lerp(a?.dividerColor, b?.dividerColor, t), ); } @override int get hashCode => Object.hash( backgroundColor, elevation, surfaceTintColor, side, shape, headerTextStyle, headerHintStyle, constraints, dividerColor, ); @override bool operator ==(Object other) { if (identical(this, other)) { return true; } if (other.runtimeType != runtimeType) { return false; } return other is SearchViewThemeData && other.backgroundColor == backgroundColor && other.elevation == elevation && other.surfaceTintColor == surfaceTintColor && other.side == side && other.shape == shape && other.headerTextStyle == headerTextStyle && other.headerHintStyle == headerHintStyle && other.constraints == constraints && other.dividerColor == dividerColor; } @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<Color?>('backgroundColor', backgroundColor, defaultValue: null)); properties.add(DiagnosticsProperty<double?>('elevation', elevation, defaultValue: null)); properties.add(DiagnosticsProperty<Color?>('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(DiagnosticsProperty<BorderSide?>('side', side, defaultValue: null)); properties.add(DiagnosticsProperty<OutlinedBorder?>('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle?>('headerTextStyle', headerTextStyle, defaultValue: null)); properties.add(DiagnosticsProperty<TextStyle?>('headerHintStyle', headerHintStyle, defaultValue: null)); properties.add(DiagnosticsProperty<BoxConstraints>('constraints', constraints, defaultValue: null)); properties.add(DiagnosticsProperty<Color?>('dividerColor', dividerColor, defaultValue: null)); } // Special case because BorderSide.lerp() doesn't support null arguments static BorderSide? _lerpSides(BorderSide? a, BorderSide? b, double t) { if (a == null || b == null) { return null; } if (identical(a, b)) { return a; } return BorderSide.lerp(a, b, t); } } /// An inherited widget that defines the configuration in this widget's /// descendants for search view created by the [SearchAnchor] widget. /// /// A search view theme can be specified as part of the overall Material theme using /// [ThemeData.searchViewTheme]. /// /// See also: /// /// * [SearchViewThemeData], which describes the actual configuration of a search view /// theme. class SearchViewTheme extends InheritedWidget { /// Creates a const theme that controls the configurations for the search view /// created by the [SearchAnchor] widget. const SearchViewTheme({ super.key, required this.data, required super.child, }); /// The properties used for all descendant [SearchAnchor] widgets. final SearchViewThemeData data; /// Returns the configuration [data] from the closest [SearchViewTheme] ancestor. /// If there is no ancestor, it returns [ThemeData.searchViewTheme]. /// /// Typical usage is as follows: /// /// ```dart /// SearchViewThemeData theme = SearchViewTheme.of(context); /// ``` static SearchViewThemeData of(BuildContext context) { final SearchViewTheme? searchViewTheme = context.dependOnInheritedWidgetOfExactType<SearchViewTheme>(); return searchViewTheme?.data ?? Theme.of(context).searchViewTheme; } @override bool updateShouldNotify(SearchViewTheme oldWidget) => data != oldWidget.data; }