-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use page title text by default if top bar title not provided
- Loading branch information
Showing
10 changed files
with
269 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
lib/src/content/components/main_content/wolt_modal_sheet_top_bar_title.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter/scheduler.dart'; | ||
import 'package:wolt_modal_sheet/src/modal_page/wolt_modal_sheet_page.dart'; | ||
|
||
/// A widget to display the top bar title in a modal sheet. | ||
/// | ||
/// It tries to display the title in the following order of preference: | ||
/// - The `topBarTitle` widget if it's not null. | ||
/// - The text data in `pageTitle` if it's a `Text` widget. | ||
/// - The first text descendant of the `pageTitle` if it's not a `Text` widget and has a | ||
/// [Text] descendant. | ||
/// - If none of the above are applicable, it defaults to a `SizedBox.shrink`. | ||
class WoltModalSheetTopBarTitle extends StatefulWidget { | ||
const WoltModalSheetTopBarTitle({ | ||
Key? key, | ||
required this.page, | ||
required this.pageTitleKey, | ||
}) : super(key: key); | ||
|
||
final WoltModalSheetPage page; | ||
final GlobalKey pageTitleKey; | ||
|
||
@override | ||
State<WoltModalSheetTopBarTitle> createState() => _WoltModalSheetTopBarTitleState(); | ||
} | ||
|
||
class _WoltModalSheetTopBarTitleState extends State<WoltModalSheetTopBarTitle> { | ||
String? pageTitleText; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
SchedulerBinding.instance.addPostFrameCallback((_) { | ||
_extractPageTitleText(); | ||
}); | ||
} | ||
|
||
void _extractPageTitleText() { | ||
final isPageTitleTextWidget = widget.page.pageTitle is Text; | ||
final pageTitleElement = widget.pageTitleKey.currentContext; | ||
|
||
if (widget.page.topBarTitle != null || isPageTitleTextWidget) { | ||
return; | ||
} else if (pageTitleElement != null) { | ||
_visitAllDescendants(pageTitleElement); | ||
} | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
final topBarTitle = widget.page.topBarTitle; | ||
final pageTitleText = | ||
(widget.page.pageTitle is Text) ? (widget.page.pageTitle as Text).data : this.pageTitleText; | ||
|
||
if (topBarTitle != null) { | ||
return topBarTitle; | ||
} else if (pageTitleText != null) { | ||
return Row( | ||
children: [ | ||
const SizedBox(width: 72), | ||
Expanded( | ||
child: Text( | ||
pageTitleText, | ||
style: Theme.of(context).textTheme.titleSmall, | ||
textAlign: TextAlign.center, | ||
overflow: TextOverflow.ellipsis, | ||
maxLines: 1, | ||
), | ||
), | ||
const SizedBox(width: 72), | ||
], | ||
); | ||
} | ||
return const SizedBox.shrink(); | ||
} | ||
|
||
// This function visits all descendants of an Element until it finds a Text widget. | ||
// It could potentially have a performance impact if the descendant Text widget is deeply nested. | ||
// However, since it stops visiting as soon as it finds a Text widget, | ||
// the impact should be minimal unless the widget tree is exceptionally large or dense. | ||
void _visitAllDescendants(BuildContext element) { | ||
element.visitChildElements((childElement) { | ||
if (childElement.widget is Text) { | ||
setState(() { | ||
pageTitleText = (childElement.widget as Text).data; | ||
}); | ||
return; // stop visiting other children | ||
} | ||
// If it's not a Text widget, continue visiting its descendants | ||
_visitAllDescendants(childElement); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
68 changes: 68 additions & 0 deletions
68
test/content/components/main_content/wolt_modal_sheet_top_bar_title_test.dart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
import 'package:wolt_modal_sheet/src/content/components/main_content/wolt_modal_sheet_top_bar_title.dart'; | ||
import 'package:wolt_modal_sheet/wolt_modal_sheet.dart'; | ||
|
||
void main() { | ||
group('WoltModalSheetTopBarTitle tests', () { | ||
// Global key to be used for pageTitle widget | ||
final GlobalKey pageTitleKey = GlobalKey(); | ||
|
||
testWidgets('should display top bar title when provided', (tester) async { | ||
await tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: WoltModalSheetTopBarTitle( | ||
page: WoltModalSheetPage.withSingleChild( | ||
child: const SizedBox.shrink(), | ||
topBarTitle: const Text('Top Bar Title'), | ||
pageTitle: const Text('Page Title'), | ||
), | ||
pageTitleKey: pageTitleKey, | ||
), | ||
), | ||
), | ||
); | ||
await tester.pumpAndSettle(); | ||
expect(find.text('Top Bar Title'), findsOneWidget); | ||
expect(find.text('Page Title'), findsNothing); | ||
}); | ||
|
||
testWidgets('should use page title when top bar title is not provided and page title is Text', | ||
(tester) async { | ||
await tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: WoltModalSheetTopBarTitle( | ||
page: WoltModalSheetPage.withSingleChild( | ||
child: const SizedBox.shrink(), | ||
pageTitle: Text('Page Title', key: pageTitleKey), | ||
), | ||
pageTitleKey: pageTitleKey, | ||
), | ||
), | ||
), | ||
); | ||
await tester.pumpAndSettle(); | ||
expect(find.text('Page Title'), findsOneWidget); | ||
}); | ||
|
||
testWidgets('should display nothing when neither top bar title nor page title is provided', | ||
(tester) async { | ||
await tester.pumpWidget( | ||
MaterialApp( | ||
home: Scaffold( | ||
body: WoltModalSheetTopBarTitle( | ||
page: WoltModalSheetPage.withSingleChild( | ||
child: const SizedBox.shrink(), | ||
), | ||
pageTitleKey: pageTitleKey, | ||
), | ||
), | ||
), | ||
); | ||
await tester.pumpAndSettle(); | ||
expect(tester.element(find.byType(WoltModalSheetTopBarTitle).at(0)).size, Size.zero); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_test/flutter_test.dart'; | ||
|
||
/// This is a template for widget tests. | ||
/// It is meant to be copied and pasted into a new file and then modified to fit the widget or feature you're testing | ||
/// An example of a test files that uses this template are: | ||
/// [test/settings/task_history/task_history_group_task_list_v2_test.dart] | ||
/// [test/localizations/localizations_test.dart] | ||
/// Confluence page with more inspiration: | ||
/// https://woltwide.atlassian.net/wiki/spaces/MAL/pages/3215262013/Widget+and+Unit+tests+for+a+new+features | ||
void main() { | ||
/// Name of the widget you're testing | ||
group('Widget tests group description', () { | ||
/// Registers a function to be run once before all tests. | ||
/// This is where you should register all fallback values for fakes | ||
setUpAll(() {}); | ||
|
||
/// This is a setup method that will be called everytime before each test. | ||
/// Use it to initialize and register mocks. | ||
/// Avoid stubbing on top level, rather do it in the method group setup callback or test case itself. | ||
/// If you need test objects to be created, do it in the group or test case itself. | ||
/// | ||
/// only do generic setup here, if you need to do specific setup for a test case, do it in the test case | ||
setUp(() {}); | ||
|
||
/// This is a teardown method that will be called after each test | ||
/// use it to dispose of mocks and fakes if needed | ||
tearDown(() {}); | ||
|
||
/// If widget functionality is very complex and might be divided to a smaller logical groups, | ||
/// test suite should be split to a smaller groups to ease understanding. | ||
/// Any setup that is specific to the subgroup and needs to be done once should be done in the subgroup's setup method | ||
/// otherwise in the test case itself | ||
group('subgroup-1', () { | ||
/// You can use the setup method to do stubbing for all test cases. If you need to do specific stubbing for a | ||
/// test case, do it in the test case itself. | ||
setUp(() {}); | ||
|
||
/// Each test case should have a name that describes what it is testing and what the expected result is. | ||
/// Don't test too much in one case. If you need to test multiple things, create multiple test cases. | ||
/// Ideally, start the name with the word 'should' to make it clear what the expected result is and use the | ||
/// word 'when' to describe a specific scenario. | ||
testWidgets('should <expected result> when <action to perform>', (tester) async { | ||
/// Arrange | ||
/// Create test objects and stub methods here | ||
// Set up needed data | ||
await tester.pumpWidget( | ||
const MaterialApp(home: SizedBox.shrink() /* Insert your widget to test here */), | ||
); | ||
await tester.pumpAndSettle(); | ||
|
||
/// Act | ||
/// Call the method you're testing | ||
// Perform Step 1 | ||
// Perform Step 2 | ||
|
||
/// Assert | ||
/// Verify that the method did what it was supposed to do | ||
// Assert that steps reached <expected result> | ||
expect( | ||
'Actual result', | ||
'Expected result', | ||
reason: 'Failure reason', | ||
); | ||
}); | ||
|
||
testWidgets('should <expected result 2> when <action to perform 2>', (tester) async {}); | ||
}); | ||
|
||
group('subgroup-2', () { | ||
setUp(() {}); | ||
|
||
testWidgets('should <expected result 1> when <actions to perform 1>', (tester) async {}); | ||
|
||
testWidgets('should <expected result 2> when <actions to perform 2>', (tester) async {}); | ||
}); | ||
}); | ||
} |