debug.dart 4.58 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/foundation.dart';
6 7 8
import 'package:flutter/widgets.dart';

import 'material.dart';
9
import 'material_localizations.dart';
10
import 'scaffold.dart' show Scaffold;
11

12
/// Asserts that the given context has a [Material] ancestor.
13
///
14 15 16
/// Used by many material design widgets to make sure that they are
/// only used in contexts where they can print ink onto some material.
///
17
/// To call this function, use the following pattern, typically in the
18
/// relevant Widget's build method:
19 20 21 22 23 24
///
/// ```dart
/// assert(debugCheckHasMaterial(context));
/// ```
///
/// Does nothing if asserts are disabled. Always returns true.
25 26
bool debugCheckHasMaterial(BuildContext context) {
  assert(() {
27
    if (context.widget is! Material && context.findAncestorWidgetOfExactType<Material>() == null) {
28 29 30 31 32 33
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('No Material widget found.'),
        ErrorDescription(
          '${context.widget.runtimeType} widgets require a Material '
          'widget ancestor.\n'
          'In material design, most widgets are conceptually "printed" on '
34
          "a sheet of material. In Flutter's material library, that "
35 36 37 38 39 40 41 42 43 44 45 46
          'material is represented by the Material widget. It is the '
          'Material widget that renders ink splashes, for instance. '
          'Because of this, many material library widgets require that '
          'there be a Material widget in the tree above them.'
        ),
        ErrorHint(
          'To introduce a Material widget, you can either directly '
          'include one, or use a widget that contains Material itself, '
          'such as a Card, Dialog, Drawer, or Scaffold.',
        ),
        ...context.describeMissingAncestor(expectedAncestorType: Material)
      ]
Hixie's avatar
Hixie committed
47 48 49
      );
    }
    return true;
50
  }());
51 52
  return true;
}
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71


/// Asserts that the given context has a [Localizations] ancestor that contains
/// a [MaterialLocalizations] delegate.
///
/// Used by many material design widgets to make sure that they are
/// only used in contexts where they have access to localizations.
///
/// To call this function, use the following pattern, typically in the
/// relevant Widget's build method:
///
/// ```dart
/// assert(debugCheckHasMaterialLocalizations(context));
/// ```
///
/// Does nothing if asserts are disabled. Always returns true.
bool debugCheckHasMaterialLocalizations(BuildContext context) {
  assert(() {
    if (Localizations.of<MaterialLocalizations>(context, MaterialLocalizations) == null) {
72 73 74 75 76 77 78
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('No MaterialLocalizations found.'),
        ErrorDescription(
          '${context.widget.runtimeType} widgets require MaterialLocalizations '
          'to be provided by a Localizations widget ancestor.'
        ),
        ErrorDescription(
79
          'Localizations are used to generate many different messages, labels, '
80 81 82 83 84 85 86 87 88 89
          'and abbreviations which are used by the material library.'
        ),
        ErrorHint(
          'To introduce a MaterialLocalizations, either use a '
          'MaterialApp at the root of your application to include them '
          'automatically, or add a Localization widget with a '
          'MaterialLocalizations delegate.'
        ),
        ...context.describeMissingAncestor(expectedAncestorType: MaterialLocalizations)
      ]);
90 91 92 93 94
    }
    return true;
  }());
  return true;
}
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110

/// Asserts that the given context has a [Scaffold] ancestor.
///
/// Used by various widgets to make sure that they are only used in an
/// appropriate context.
///
/// To invoke this function, use the following pattern, typically in the
/// relevant Widget's build method:
///
/// ```dart
/// assert(debugCheckHasScaffold(context));
/// ```
///
/// Does nothing if asserts are disabled. Always returns true.
bool debugCheckHasScaffold(BuildContext context) {
  assert(() {
111
    if (context.widget is! Scaffold && context.findAncestorWidgetOfExactType<Scaffold>() == null) {
112 113 114 115 116
      throw FlutterError.fromParts(<DiagnosticsNode>[
        ErrorSummary('No Scaffold widget found.'),
        ErrorDescription('${context.widget.runtimeType} widgets require a Scaffold widget ancestor.'),
        ...context.describeMissingAncestor(expectedAncestorType: Scaffold),
        ErrorHint(
117 118
          'Typically, the Scaffold widget is introduced by the MaterialApp or '
          'WidgetsApp widget at the top of your application widget tree.'
119 120
        )
      ]);
121 122 123 124 125
    }
    return true;
  }());
  return true;
}