action_icons_theme.dart 5.94 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
// 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 ?? backButtonIconBuilder,
      closeButtonIconBuilder: closeButtonIconBuilder ?? closeButtonIconBuilder,
      drawerButtonIconBuilder: drawerButtonIconBuilder ?? drawerButtonIconBuilder,
      endDrawerButtonIconBuilder: endDrawerButtonIconBuilder ?? 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.
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;
}