Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add theme extensions for wolt modal sheet #44

Merged
merged 1 commit into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
316 changes: 178 additions & 138 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,168 +168,208 @@ This package has 4 example projects.

### Example app

The [example](./example/) app demonstrates how to display a two-page modal
sheet.
The [example](./example/) app demonstrates how to display a two-pages modal
sheet that can be customized for dark and light themes
using [WoltModalSheetThemeData](./lib/src/theme/wolt_modal_sheet_theme_data.dart) theme
extension.

```dart
class MainApp extends StatelessWidget {
const MainApp({super.key});

@override
Widget build(BuildContext context) {
final pageIndexNotifier = ValueNotifier(0);

WoltModalSheetPage page1(BuildContext modalSheetContext) {
return WoltModalSheetPage.withSingleChild(
stickyActionBar: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
ElevatedButton(
onPressed: () => Navigator.of(modalSheetContext).pop(),
child: const SizedBox(
height: 56.0,
width: double.infinity,
child: Center(child: Text('Cancel')),
),
Widget build(BuildContext context) {
final pageIndexNotifier = ValueNotifier(0);

WoltModalSheetPage page1(BuildContext modalSheetContext, TextTheme textTheme) {
return WoltModalSheetPage.withSingleChild(
hasSabGradient: false,
stickyActionBar: Padding(
padding: const EdgeInsets.all(_pagePadding),
child: Column(
children: [
ElevatedButton(
onPressed: () => Navigator.of(modalSheetContext).pop(),
child: const SizedBox(
height: _buttonHeight,
width: double.infinity,
child: Center(child: Text('Cancel')),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => pageIndexNotifier.value = pageIndexNotifier.value + 1,
child: const SizedBox(
height: 56.0,
width: double.infinity,
child: Center(child: Text('Next page')),
),
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => pageIndexNotifier.value = pageIndexNotifier.value + 1,
child: const SizedBox(
height: _buttonHeight,
width: double.infinity,
child: Center(child: Text('Next page')),
),
],
),
),
topBarTitle: Text('Pagination', style: Theme.of(context).textTheme.titleSmall),
isTopBarLayerAlwaysVisible: true,
trailingNavBarWidget: IconButton(
padding: const EdgeInsets.all(16),
icon: const Icon(Icons.close),
onPressed: Navigator.of(modalSheetContext).pop,
),
],
),
child: const Padding(
padding: EdgeInsets.fromLTRB(16, 16, 16, 150),
child: Text(
'''
),
topBarTitle: Text('Pagination', style: textTheme.titleSmall),
isTopBarLayerAlwaysVisible: true,
trailingNavBarWidget: IconButton(
padding: const EdgeInsets.all(_pagePadding),
icon: const Icon(Icons.close),
onPressed: Navigator.of(modalSheetContext).pop,
),
child: const Padding(
padding: EdgeInsets.fromLTRB(
_pagePadding,
_pagePadding,
_pagePadding,
_bottomPaddingForButton,
),
child: Text(
'''
Pagination involves a sequence of screens the user navigates sequentially. We chose a lateral motion for these transitions. When proceeding forward, the next screen emerges from the right; moving backward, the screen reverts to its original position. We felt that sliding the next screen entirely from the right could be overly distracting. As a result, we decided to move and fade in the next page using 30% of the modal side.
''',
)),
);
}

WoltModalSheetPage page2(BuildContext modalSheetContext) {
return WoltModalSheetPage.withCustomSliverList(
stickyActionBar: Padding(
padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
child: ElevatedButton(
onPressed: () {
Navigator.of(modalSheetContext).pop();
pageIndexNotifier.value = 0;
},
child: const SizedBox(
height: 56.0,
width: double.infinity,
child: Center(child: Text('Close')),
),
)),
);
}

WoltModalSheetPage page2(BuildContext modalSheetContext, TextTheme textTheme) {
return WoltModalSheetPage.withCustomSliverList(
stickyActionBar: Padding(
padding:
const EdgeInsets.fromLTRB(_pagePadding, _pagePadding / 4, _pagePadding, _pagePadding),
child: ElevatedButton(
onPressed: () {
Navigator.of(modalSheetContext).pop();
pageIndexNotifier.value = 0;
},
child: const SizedBox(
height: _buttonHeight,
width: double.infinity,
child: Center(child: Text('Close')),
),
),
pageTitle: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Material Colors',
style:
Theme.of(context).textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold),
),
),
pageTitle: Padding(
padding: const EdgeInsets.symmetric(horizontal: _pagePadding),
child: Text(
'Material Colors',
style: textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold),
),
heroImageHeight: 200,
heroImage: const Image(
image: AssetImage('lib/assets/images/material_colors_hero.png'),
fit: BoxFit.cover,
),
heroImage: Image(
image: AssetImage(
'lib/assets/images/material_colors_hero${_isLightTheme ? '_light' : '_dark'}.png',
),
leadingNavBarWidget: IconButton(
padding: const EdgeInsets.all(16),
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () => pageIndexNotifier.value = pageIndexNotifier.value - 1,
fit: BoxFit.cover,
),
leadingNavBarWidget: IconButton(
padding: const EdgeInsets.all(_pagePadding),
icon: const Icon(Icons.arrow_back_rounded),
onPressed: () => pageIndexNotifier.value = pageIndexNotifier.value - 1,
),
trailingNavBarWidget: IconButton(
padding: const EdgeInsets.all(_pagePadding),
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(modalSheetContext).pop();
pageIndexNotifier.value = 0;
},
),
sliverList: SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => ColorTile(color: allMaterialColors[index]),
childCount: allMaterialColors.length,
),
trailingNavBarWidget: IconButton(
padding: const EdgeInsets.all(16),
icon: const Icon(Icons.close),
onPressed: () {
Navigator.of(modalSheetContext).pop();
pageIndexNotifier.value = 0;
},
),
);
}

return MaterialApp(
themeMode: _isLightTheme ? ThemeMode.light : ThemeMode.dark,
theme: ThemeData.light(useMaterial3: true).copyWith(
extensions: const <ThemeExtension>[
WoltModalSheetThemeData(
heroImageHeight: _heroImageHeight,
topBarShadowColor: _lightThemeShadowColor,
modalBarrierColor: Colors.black54,
),
sliverList: SliverList(
delegate: SliverChildBuilderDelegate(
(_, index) => ColorTile(color: allMaterialColors[index]),
childCount: allMaterialColors.length,
),
],
),
darkTheme: ThemeData.dark(useMaterial3: true).copyWith(
extensions: const <ThemeExtension>[
WoltModalSheetThemeData(
topBarShadowColor: _darkThemeShadowColor,
modalBarrierColor: Colors.white12,
sabGradientColor: _darkSabGradientColor,
dialogShape: BeveledRectangleBorder(),
bottomSheetShape: BeveledRectangleBorder(),
),
);
}

return MaterialApp(
theme: ThemeData(colorSchemeSeed: const Color(0xFF009DE0), useMaterial3: true),
home: Scaffold(
body: Builder(
builder: (context) {
return Center(
child: SizedBox(
width: 200,
child: ElevatedButton(
onPressed: () {
WoltModalSheet.show<void>(
pageIndexNotifier: pageIndexNotifier,
context: context,
pageListBuilder: (modalSheetContext) {
return [
page1(modalSheetContext),
page2(modalSheetContext),
];
},
modalTypeBuilder: (context) {
final size = MediaQuery.of(context).size.width;
if (size < 768) {
return WoltModalType.bottomSheet;
} else {
return WoltModalType.dialog;
}
},
onModalDismissedWithBarrierTap: () {
debugPrint('Closed modal sheet with barrier tap');
Navigator.of(context).pop();
pageIndexNotifier.value = 0;
},
maxDialogWidth: 560,
minDialogWidth: 400,
minPageHeight: 0.4,
maxPageHeight: 0.9,
);
},
child: const SizedBox(
height: 56.0,
child: Center(child: Text('Show Modal Sheet')),
],
),
home: Scaffold(
body: Builder(
builder: (context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text('Light Theme'),
Padding(
padding: const EdgeInsets.all(_pagePadding),
child: Switch(
value: !_isLightTheme,
onChanged: (_) => setState(() => _isLightTheme = !_isLightTheme),
),
),
const Text('Dark Theme'),
],
),
ElevatedButton(
onPressed: () {
WoltModalSheet.show<void>(
pageIndexNotifier: pageIndexNotifier,
context: context,
pageListBuilder: (modalSheetContext) {
final textTheme = Theme.of(context).textTheme;
return [
page1(modalSheetContext, textTheme),
page2(modalSheetContext, textTheme),
];
},
modalTypeBuilder: (context) {
final size = MediaQuery.of(context).size.width;
if (size < _pageBreakpoint) {
return WoltModalType.bottomSheet;
} else {
return WoltModalType.dialog;
}
},
onModalDismissedWithBarrierTap: () {
debugPrint('Closed modal sheet with barrier tap');
Navigator.of(context).pop();
pageIndexNotifier.value = 0;
},
maxDialogWidth: 560,
minDialogWidth: 400,
minPageHeight: 0.0,
maxPageHeight: 0.9,
);
},
child: const SizedBox(
height: _buttonHeight,
width: _buttonWidth,
child: Center(child: Text('Show Modal Sheet')),
),
),
);
},
),
],
);
},
),
);
}
),
);
}
```

The code snippet above produces the following:
</br>
</br>
![Example app](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/wms_example.gif?raw=true)
![Example app](https://github.com/woltapp/wolt_modal_sheet/blob/main/doc/example_app_with_theme_extensions?raw=true)

### Playground app with imperative navigation

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class AddWaterDescriptionModalPage {
required VoidCallback onClosed,
}) {
return WoltModalSheetPage.withSingleChild(
heroImageHeight: 200,
heroImage: const Image(
image: AssetImage('lib/assets/images/add_water_description.png'),
fit: BoxFit.cover,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ class ServeOrOfferModalPage {
required VoidCallback onClosed,
}) {
return WoltModalSheetPage.withSingleChild(
heroImageHeight: 200,
heroImage: const Image(
image: AssetImage('lib/assets/images/coffee_is_ready.png'),
fit: BoxFit.cover,
Expand Down
2 changes: 1 addition & 1 deletion demo_ui_components/lib/src/colors/wolt_colors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class WoltColors {
static const blue8 = Color(0xFFEBF8FD);

static const green = Color(0xFF1FC70A);
static const green64 = Color(0xFF70DB62);
static const green64 = Color(0xFF5DD64E);
static const green48 = Color(0xFF94E58A);
static const green16 = Color(0xFFDBF6D8);
static const green8 = Color(0xFFEDFBEC);
Expand Down
2 changes: 1 addition & 1 deletion demo_ui_components/lib/src/text/modal_sheet_title.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ModalSheetTitle extends StatelessWidget {
child: Text(
text,
textAlign: textAlign,
style: Theme.of(context).textTheme.headlineMedium!.copyWith(fontWeight: FontWeight.bold),
style: Theme.of(context).textTheme.headlineSmall!.copyWith(fontWeight: FontWeight.bold),
),
);
}
Expand Down
Binary file added doc/example_app_with_theme_extensions.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed doc/wms_example.gif
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading