Skip to content

Commit

Permalink
Add theme extensions for wolt modal sheet
Browse files Browse the repository at this point in the history
  • Loading branch information
ulusoyca committed Aug 19, 2023
1 parent 4a7338d commit d85d6f4
Show file tree
Hide file tree
Showing 32 changed files with 977 additions and 364 deletions.
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

0 comments on commit d85d6f4

Please sign in to comment.