blob: 28de5cd2a3086cf5086bcdd4f4e68b63a316a6a4 [file] [log] [blame]
// 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 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'action_buttons.dart';
import 'theme.dart';
// Examples can assume:
// late BuildContext context;
/// A [ActionIconThemeData] that overrides the default icons of
/// [BackButton], [CloseButton], [DrawerButton], and [EndDrawerButton] with
/// [ActionIconTheme.of] or the overall [Theme]'s [ThemeData.actionIconTheme].
@immutable
class ActionIconThemeData with Diagnosticable {
/// Creates an [ActionIconThemeData].
///
/// The builders [backButtonIconBuilder], [closeButtonIconBuilder],
/// [drawerButtonIconBuilder], [endDrawerButtonIconBuilder] may be null.
const ActionIconThemeData({
this.backButtonIconBuilder,
this.closeButtonIconBuilder,
this.drawerButtonIconBuilder,
this.endDrawerButtonIconBuilder,
});
/// Overrides [BackButtonIcon]'s icon.
///
/// If [backButtonIconBuilder] is null, then [BackButtonIcon]
/// fallbacks to the platform's default back button icon.
final WidgetBuilder? backButtonIconBuilder;
/// Overrides [CloseButtonIcon]'s icon.
///
/// If [closeButtonIconBuilder] is null, then [CloseButtonIcon]
/// fallbacks to the platform's default close button icon.
final WidgetBuilder? closeButtonIconBuilder;
/// Overrides [DrawerButtonIcon]'s icon.
///
/// If [drawerButtonIconBuilder] is null, then [DrawerButtonIcon]
/// fallbacks to the platform's default drawer button icon.
final WidgetBuilder? drawerButtonIconBuilder;
/// Overrides [EndDrawerButtonIcon]'s icon.
///
/// If [endDrawerButtonIconBuilder] is null, then [EndDrawerButtonIcon]
/// fallbacks to the platform's default end drawer button icon.
final WidgetBuilder? endDrawerButtonIconBuilder;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
ActionIconThemeData copyWith({
WidgetBuilder? backButtonIconBuilder,
WidgetBuilder? closeButtonIconBuilder,
WidgetBuilder? drawerButtonIconBuilder,
WidgetBuilder? endDrawerButtonIconBuilder,
}) {
return ActionIconThemeData(
backButtonIconBuilder: backButtonIconBuilder ?? this.backButtonIconBuilder,
closeButtonIconBuilder: closeButtonIconBuilder ?? this.closeButtonIconBuilder,
drawerButtonIconBuilder: drawerButtonIconBuilder ?? this.drawerButtonIconBuilder,
endDrawerButtonIconBuilder: endDrawerButtonIconBuilder ?? this.endDrawerButtonIconBuilder,
);
}
/// Linearly interpolate between two action icon themes.
static ActionIconThemeData? lerp(ActionIconThemeData? a, ActionIconThemeData? b, double t) {
if (a == null && b == null) {
return null;
}
return ActionIconThemeData(
backButtonIconBuilder: t < 0.5 ? a?.backButtonIconBuilder : b?.backButtonIconBuilder,
closeButtonIconBuilder: t < 0.5 ? a?.closeButtonIconBuilder : b?.closeButtonIconBuilder,
drawerButtonIconBuilder: t < 0.5 ? a?.drawerButtonIconBuilder : b?.drawerButtonIconBuilder,
endDrawerButtonIconBuilder:
t < 0.5 ? a?.endDrawerButtonIconBuilder : b?.endDrawerButtonIconBuilder,
);
}
@override
int get hashCode {
final List<Object?> values = <Object?>[
backButtonIconBuilder,
closeButtonIconBuilder,
drawerButtonIconBuilder,
endDrawerButtonIconBuilder,
];
return Object.hashAll(values);
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other.runtimeType != runtimeType) {
return false;
}
return other is ActionIconThemeData &&
other.backButtonIconBuilder == backButtonIconBuilder &&
other.closeButtonIconBuilder == closeButtonIconBuilder &&
other.drawerButtonIconBuilder == drawerButtonIconBuilder &&
other.endDrawerButtonIconBuilder == endDrawerButtonIconBuilder;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(
DiagnosticsProperty<WidgetBuilder>(
'backButtonIconBuilder',
backButtonIconBuilder,
defaultValue: null,
),
);
properties.add(
DiagnosticsProperty<WidgetBuilder>(
'closeButtonIconBuilder',
closeButtonIconBuilder,
defaultValue: null,
),
);
properties.add(
DiagnosticsProperty<WidgetBuilder>(
'drawerButtonIconBuilder',
drawerButtonIconBuilder,
defaultValue: null,
),
);
properties.add(
DiagnosticsProperty<WidgetBuilder>(
'endDrawerButtonIconBuilder',
endDrawerButtonIconBuilder,
defaultValue: null,
),
);
}
}
/// An inherited widget that overrides the default icon of [BackButtonIcon],
/// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] in this
/// widget's subtree.
///
/// {@tool dartpad}
/// This example shows how to define custom builders for drawer and back
/// buttons.
///
/// ** See code in examples/api/lib/material/action_buttons/action_icon_theme.0.dart **
/// {@end-tool}
class ActionIconTheme extends InheritedTheme {
/// Creates a theme that overrides the default icon of [BackButtonIcon],
/// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] in this
/// widget's subtree.
const ActionIconTheme({super.key, required this.data, required super.child});
/// Specifies the default icon overrides for descendant [BackButtonIcon],
/// [CloseButtonIcon], [DrawerButtonIcon], and [EndDrawerButtonIcon] widgets.
final ActionIconThemeData data;
/// The closest instance of this class that encloses the given context.
///
/// If there is no enclosing [ActionIconTheme] widget, then
/// [ThemeData.actionIconTheme] is used.
///
/// Typical usage is as follows:
///
/// ```dart
/// ActionIconThemeData? theme = ActionIconTheme.of(context);
/// ```
static ActionIconThemeData? of(BuildContext context) {
final ActionIconTheme? actionIconTheme =
context.dependOnInheritedWidgetOfExactType<ActionIconTheme>();
return actionIconTheme?.data ?? Theme.of(context).actionIconTheme;
}
@override
Widget wrap(BuildContext context, Widget child) {
return ActionIconTheme(data: data, child: child);
}
@override
bool updateShouldNotify(ActionIconTheme oldWidget) => data != oldWidget.data;
}