diff --git a/forui/example/pubspec.lock b/forui/example/pubspec.lock index 429bcadf4..de2dfafb5 100644 --- a/forui/example/pubspec.lock +++ b/forui/example/pubspec.lock @@ -214,6 +214,11 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_localizations: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" flutter_svg: dependency: transitive description: @@ -297,6 +302,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + intl: + dependency: transitive + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" io: dependency: transitive description: diff --git a/forui/lib/src/widgets/text_field/text_field.dart b/forui/lib/src/widgets/text_field/text_field.dart index 80042b845..c1d84704f 100644 --- a/forui/lib/src/widgets/text_field/text_field.dart +++ b/forui/lib/src/widgets/text_field/text_field.dart @@ -1,8 +1,11 @@ +import 'dart:io'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:forui/forui.dart'; part 'text_field_state.dart'; @@ -475,13 +478,64 @@ final class FTextField extends StatefulWidget { this.suffixIcon, }); + /// Creates a [FTextField] configured for emails. + const FTextField.email({ + this.style, + this.hint = 'Email', + this.magnifierConfiguration, + this.controller, + this.focusNode, + this.keyboardType = TextInputType.emailAddress, + this.textInputAction, + this.textCapitalization = TextCapitalization.none, + this.textAlign = TextAlign.start, + this.textAlignVertical, + this.textDirection, + this.autofocus = false, + this.statesController, + this.obscureText = false, + this.autocorrect = false, + this.smartDashesType, + this.smartQuotesType, + this.enableSuggestions = true, + this.minLines, + this.maxLines = 1, + this.expands = false, + this.readOnly = false, + this.showCursor, + this.maxLength, + this.maxLengthEnforcement, + this.onChange, + this.onEditingComplete, + this.onSubmit, + this.onAppPrivateCommand, + this.inputFormatters, + this.enabled = true, + this.ignorePointers, + this.enableInteractSelection = true, + this.selectionControls, + this.dragStartBehavior = DragStartBehavior.start, + this.scrollPhysics, + this.scrollController, + this.autofillHints = const [AutofillHints.email], + this.restorationId, + this.scribbleEnabled = true, + this.enableIMEPersonalizedLearning = true, + this.contextMenuBuilder = _defaultContextMenuBuilder, + this.canRequestFocus = true, + this.undoController, + this.spellCheckConfiguration, + this.label, + this.suffixIcon, + }); + /// Creates a [FTextField] configured for passwords. /// /// [autofillHints] defaults to [AutofillHints.password]. It should be overridden with [AutofillHints.newPassword] /// when handling the creation of new passwords. const FTextField.password({ this.style, - this.hint, + this.hint = 'Password', this.magnifierConfiguration, this.controller, this.focusNode, diff --git a/forui/lib/src/widgets/text_field/text_field_state.dart b/forui/lib/src/widgets/text_field/text_field_state.dart index 30ed03a78..a430ab8f9 100644 --- a/forui/lib/src/widgets/text_field/text_field_state.dart +++ b/forui/lib/src/widgets/text_field/text_field_state.dart @@ -1,5 +1,6 @@ part of 'text_field.dart'; + class _State extends State { late final WidgetStatesController controller; @@ -14,8 +15,9 @@ class _State extends State { Widget build(BuildContext context) { final theme = context.theme; final style = widget.style ?? theme.textFieldStyle; + final materialLocalizations = Localizations.of(context, MaterialLocalizations); - return MergeSemantics( + final textField = MergeSemantics( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -27,33 +29,51 @@ class _State extends State { style: style.label, ), ), - Theme( - // The selection colors are defined in a Theme instead of TextField since TextField does not expose parameters - // for overriding selectionHandleColor. - data: Theme.of(context).copyWith( - textSelectionTheme: TextSelectionThemeData( - cursorColor: style.cursor, - selectionColor: style.cursor.withOpacity(0.4), - selectionHandleColor: style.cursor, + Material( + color: Colors.transparent, + child: Theme( + // The selection colors are defined in a Theme instead of TextField since TextField does not expose parameters + // for overriding selectionHandleColor. + data: Theme.of(context).copyWith( + textSelectionTheme: TextSelectionThemeData( + cursorColor: style.cursor, + selectionColor: style.cursor.withOpacity(0.4), + selectionHandleColor: style.cursor, + ), + cupertinoOverrideTheme: CupertinoThemeData( + primaryColor: style.cursor, + ), ), - cupertinoOverrideTheme: CupertinoThemeData( - primaryColor: style.cursor, + // This is done because InputDecoration.errorBorder and InputDecoration.focusedErrorBorder aren't shown unless an + // additional error help text is supplied. That error help text has few configuration options. + child: ValueListenableBuilder( + valueListenable: widget.statesController ?? controller, + builder: (context, states, _) { + final (enabled, focus) = states.contains(WidgetState.error) ? (style.error, style.focusedError) : (style.enabled, style.focused); + final current = states.contains(WidgetState.focused) ? focus : enabled; + return _build(context, style, current, enabled, focus); + }, ), ), - // This is done because InputDecoration.errorBorder and InputDecoration.focusedErrorBorder aren't shown unless an - // additional error help text is supplied. That error help text has few configuration options. - child: ValueListenableBuilder( - valueListenable: widget.statesController ?? controller, - builder: (context, states, _) { - final (enabled, focus) = states.contains(WidgetState.error) ? (style.error, style.focusedError) : (style.enabled, style.focused); - final current = states.contains(WidgetState.focused) ? focus : enabled; - return _build(context, style, current, enabled, focus); - }, - ), ), ], ), ); + + + if (materialLocalizations == null) { + return Localizations( + locale: Localizations.maybeLocaleOf(context) ?? const Locale('en', 'US'), + delegates: const [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + child: textField, + ); + } + + return textField; } Widget _build( diff --git a/forui/lib/src/widgets/text_field/text_field_style.dart b/forui/lib/src/widgets/text_field/text_field_style.dart index e909ec86a..192ad1df9 100644 --- a/forui/lib/src/widgets/text_field/text_field_style.dart +++ b/forui/lib/src/widgets/text_field/text_field_style.dart @@ -67,7 +67,7 @@ final class FTextFieldStyle with Diagnosticable { label = TextStyle( color: colorScheme.primary, fontSize: font.sm, - fontWeight: FontWeight.bold, + fontWeight: FontWeight.w600, ), keyboardAppearance = colorScheme.brightness, cursor = CupertinoColors.activeBlue, diff --git a/forui/pubspec.yaml b/forui/pubspec.yaml index 5374f4a88..d29f5604d 100644 --- a/forui/pubspec.yaml +++ b/forui/pubspec.yaml @@ -11,6 +11,8 @@ environment: dependencies: flutter: sdk: flutter + flutter_localizations: + sdk: flutter flutter_svg: ^2.0.10+1 forui_assets: path: ../forui_assets diff --git a/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png new file mode 100644 index 000000000..799d0c011 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-focused-text.png b/forui/test/golden/text_field/default-zinc-dark-focused-text.png new file mode 100644 index 000000000..37b8d7209 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png new file mode 100644 index 000000000..6c12cf3ff Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png new file mode 100644 index 000000000..4da75ba56 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-focused-no-text.png b/forui/test/golden/text_field/default-zinc-light-focused-no-text.png new file mode 100644 index 000000000..c373a7297 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-focused-text.png b/forui/test/golden/text_field/default-zinc-light-focused-text.png new file mode 100644 index 000000000..0880fd8bd Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png new file mode 100644 index 000000000..fa3f0a519 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/default-zinc-light-unfocused-text.png b/forui/test/golden/text_field/default-zinc-light-unfocused-text.png new file mode 100644 index 000000000..fb8b96d51 Binary files /dev/null and b/forui/test/golden/text_field/default-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png new file mode 100644 index 000000000..e08f8a27e Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-focused-text.png b/forui/test/golden/text_field/email-zinc-dark-focused-text.png new file mode 100644 index 000000000..2edbc6d47 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png new file mode 100644 index 000000000..870713685 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png new file mode 100644 index 000000000..8ceddb105 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-focused-no-text.png b/forui/test/golden/text_field/email-zinc-light-focused-no-text.png new file mode 100644 index 000000000..086646f20 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-focused-text.png b/forui/test/golden/text_field/email-zinc-light-focused-text.png new file mode 100644 index 000000000..581a24fd6 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png new file mode 100644 index 000000000..822130e02 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/email-zinc-light-unfocused-text.png b/forui/test/golden/text_field/email-zinc-light-unfocused-text.png new file mode 100644 index 000000000..e2b0b12a5 Binary files /dev/null and b/forui/test/golden/text_field/email-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png new file mode 100644 index 000000000..1f3ed516f Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png b/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png new file mode 100644 index 000000000..37b8d7209 Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png new file mode 100644 index 000000000..ffa702ad8 Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png new file mode 100644 index 000000000..4da75ba56 Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png b/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png new file mode 100644 index 000000000..394a45e1a Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-focused-text.png b/forui/test/golden/text_field/multiline-zinc-light-focused-text.png new file mode 100644 index 000000000..0880fd8bd Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png new file mode 100644 index 000000000..d6ebfc83f Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png b/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png new file mode 100644 index 000000000..fb8b96d51 Binary files /dev/null and b/forui/test/golden/text_field/multiline-zinc-light-unfocused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png b/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png new file mode 100644 index 000000000..012f2fce6 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-dark-focused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-focused-text.png b/forui/test/golden/text_field/password-zinc-dark-focused-text.png new file mode 100644 index 000000000..7ae1083ad Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-dark-focused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png b/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png new file mode 100644 index 000000000..14ca17f45 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-dark-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png b/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png new file mode 100644 index 000000000..3feb5ec27 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-dark-unfocused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-focused-no-text.png b/forui/test/golden/text_field/password-zinc-light-focused-no-text.png new file mode 100644 index 000000000..52f1e073b Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-light-focused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-focused-text.png b/forui/test/golden/text_field/password-zinc-light-focused-text.png new file mode 100644 index 000000000..13218cfa1 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-light-focused-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png b/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png new file mode 100644 index 000000000..59ba18613 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-light-unfocused-no-text.png differ diff --git a/forui/test/golden/text_field/password-zinc-light-unfocused-text.png b/forui/test/golden/text_field/password-zinc-light-unfocused-text.png new file mode 100644 index 000000000..5b7733ca4 Binary files /dev/null and b/forui/test/golden/text_field/password-zinc-light-unfocused-text.png differ diff --git a/forui/test/src/widgets/badge_test.dart b/forui/test/src/widgets/badge_golden_test.dart similarity index 100% rename from forui/test/src/widgets/badge_test.dart rename to forui/test/src/widgets/badge_golden_test.dart diff --git a/forui/test/src/widgets/button_test.dart b/forui/test/src/widgets/button_golden_test.dart similarity index 100% rename from forui/test/src/widgets/button_test.dart rename to forui/test/src/widgets/button_golden_test.dart diff --git a/forui/test/src/widgets/card_test.dart b/forui/test/src/widgets/card_golden_test.dart similarity index 100% rename from forui/test/src/widgets/card_test.dart rename to forui/test/src/widgets/card_golden_test.dart diff --git a/forui/test/src/widgets/header_test.dart b/forui/test/src/widgets/header_golden_test.dart similarity index 100% rename from forui/test/src/widgets/header_test.dart rename to forui/test/src/widgets/header_golden_test.dart diff --git a/forui/test/src/widgets/separator_test.dart b/forui/test/src/widgets/separator_golden_test.dart similarity index 100% rename from forui/test/src/widgets/separator_test.dart rename to forui/test/src/widgets/separator_golden_test.dart diff --git a/forui/test/src/widgets/switch_test.dart b/forui/test/src/widgets/switch_golden_test.dart similarity index 98% rename from forui/test/src/widgets/switch_test.dart rename to forui/test/src/widgets/switch_golden_test.dart index f575b9c00..0f463432e 100644 --- a/forui/test/src/widgets/switch_test.dart +++ b/forui/test/src/widgets/switch_golden_test.dart @@ -1,3 +1,6 @@ +@Tags(['golden']) +library; + import 'package:flutter/cupertino.dart'; import 'package:flutter_test/flutter_test.dart'; diff --git a/forui/test/src/widgets/text_field_golden_test.dart b/forui/test/src/widgets/text_field_golden_test.dart new file mode 100644 index 000000000..8f0416694 --- /dev/null +++ b/forui/test/src/widgets/text_field_golden_test.dart @@ -0,0 +1,133 @@ +@Tags(['golden']) +library; + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; + +import '../test_scaffold.dart'; + +const _text = +'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ' +'Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure ' +'dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non ' +'proident, sunt in culpa qui officia deserunt mollit anim id est laborum '; + +void main() { + group('FTextField', () { + for (final (theme, theme_, _) in TestScaffold.themes) { + for (final (focused, focused_) in [('focused', true), ('unfocused', false)]) { + for (final (text, text_) in [('text', _text), ('no-text', null)]) { + testWidgets('default - $theme - $focused', (tester) async { + final controller = text_ == null ? null : TextEditingController(text: text_); + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField( + controller: controller, + autofocus: focused_, + label: 'My Label', + hint: 'hint', + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/default-$theme-$focused-$text.png'), + ); + }); + + testWidgets('email - $theme - $focused', (tester) async { + final controller = text_ == null ? null : TextEditingController(text: text_); + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField.email( + controller: controller, + autofocus: focused_, + label: 'Email', + hint: 'janedoe@foruslabs.com', + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/email-$theme-$focused-$text.png'), + ); + }); + + testWidgets('password - $theme - $focused', (tester) async { + final controller = text_ == null ? null : TextEditingController(text: text_); + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField.password( + controller: controller, + autofocus: focused_, + label: 'Password', + hint: 'password', + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/password-$theme-$focused-$text.png'), + ); + }); + + testWidgets('multiline - $theme - $focused', (tester) async { + final controller = text_ == null ? null : TextEditingController(text: text_); + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: theme_, + child: Padding( + padding: const EdgeInsets.all(20), + child: FTextField.multiline( + controller: controller, + autofocus: focused_, + label: 'My Label', + hint: 'hint', + ), + ), + ), + ), + ); + + await tester.pumpAndSettle(); + + await expectLater( + find.byType(TestScaffold), + matchesGoldenFile('text_field/multiline-$theme-$focused-$text.png'), + ); + }); + } + + } + } + }); +} \ No newline at end of file diff --git a/forui/test/src/widgets/text_field_test.dart b/forui/test/src/widgets/text_field_test.dart new file mode 100644 index 000000000..ad580f04f --- /dev/null +++ b/forui/test/src/widgets/text_field_test.dart @@ -0,0 +1,66 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:forui/forui.dart'; + +import '../test_scaffold.dart'; + +void main() { + group('FTextField', () { + testWidgets('embedded in CupertinoApp', (tester) async { + await tester.pumpWidget( + CupertinoApp( + home: TestScaffold( + data: FThemes.zinc.light, + child: const FTextField(), + ), + ), + ); + + expect(tester.takeException(), null); + }); + + testWidgets('embedded in MaterialApp', (tester) async { + await tester.pumpWidget( + MaterialApp( + home: TestScaffold( + data: FThemes.zinc.light, + child: const FTextField(), + ), + ), + ); + + expect(tester.takeException(), null); + }); + + testWidgets('not embedded in any App', (tester) async { + await tester.pumpWidget( + TestScaffold( + data: FThemes.zinc.light, + child: const FTextField(), + ), + ); + + expect(tester.takeException(), null); + }); + + testWidgets('non-English Locale', (tester) async { + await tester.pumpWidget( + Localizations( + locale: const Locale('fr', 'FR'), + delegates: const [ + DefaultMaterialLocalizations.delegate, + DefaultCupertinoLocalizations.delegate, + DefaultWidgetsLocalizations.delegate, + ], + child: TestScaffold( + data: FThemes.zinc.light, + child: const FTextField(), + ), + ), + ); + + expect(tester.takeException(), null); + }); + }); +} \ No newline at end of file