Skip to content

Commit bad4af8

Browse files
committed
Add comprehensive Flutter extension methods
Introduces new extension methods for Widget, BuildContext, Color, EdgeInsets, String, and List<Widget> to simplify common Flutter patterns. Enhancements include navigation, theming, layout, styling, effects, gestures, and platform/media query utilities. Example usage and tests for all new extensions are provided.
1 parent 15717d4 commit bad4af8

File tree

10 files changed

+1157
-1
lines changed

10 files changed

+1157
-1
lines changed

CHANGELOG.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,79 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
This is the first release of **mayr_flutter_extensions** as a standalone Flutter-specific extension package, separated from the original `mayr_extensions` package.
1313

14+
### Added - New Extensions
15+
16+
#### 🎨 Widget Extensions - Positioning & Sizing
17+
- `positioned({top, bottom, left, right})` - Wraps widget in Positioned with custom positioning for Stack layouts
18+
- `aspectRatio(double ratio)` - Maintains aspect ratio (e.g., 16:9 for videos)
19+
- `fractionallySizedBox({widthFactor, heightFactor})` - Sizes widget as fraction of parent
20+
21+
#### 🎨 Widget Extensions - Styling
22+
- `decorated(BoxDecoration decoration)` - Wraps widget in DecoratedBox with custom decoration
23+
- `card({elevation, shape})` - Wraps widget in Material Card
24+
- `clipOval()` - Clips widget to oval shape
25+
26+
#### 🎨 Widget Extensions - Layout
27+
- `scrollable({direction})` - Wraps widget in SingleChildScrollView (vertical or horizontal)
28+
- `safeArea({top, bottom})` - Wraps widget in SafeArea with optional sides
29+
- `fittedBox({fit})` - Wraps widget in FittedBox with BoxFit options
30+
31+
#### 🎨 Widget Extensions - Effects & Gestures
32+
- `hero(String tag)` - Wraps widget in Hero for page transition animations
33+
- `rotated(int quarterTurns)` - Wraps widget in RotatedBox (rotates by 90° increments)
34+
- `transform(Matrix4 transform)` - Wraps widget in Transform with matrix transformations
35+
- `gestureDetector({onTap, onDoubleTap})` - Wraps widget in GestureDetector for gesture handling
36+
- `dismissible(Key key, {direction})` - Wraps widget in Dismissible for swipe-to-dismiss functionality
37+
38+
#### 🧭 BuildContext Extensions - Navigation
39+
- `push(Widget page)` - Navigate to new page with MaterialPageRoute
40+
- `pop([result])` - Go back with optional result
41+
- `pushReplacement(Widget page)` - Replace current route with new page
42+
- `pushNamed(String route, {arguments})` - Navigate by named route with arguments
43+
44+
#### 🧭 BuildContext Extensions - Theme Access
45+
- `theme` - Get current ThemeData
46+
- `primaryColor` - Quick access to theme primary color
47+
- `colorScheme` - Access current ColorScheme
48+
- `textTheme` - Access TextTheme styles
49+
- `isDarkMode` - Check if dark mode is active (based on theme brightness)
50+
51+
#### 🧭 BuildContext Extensions - MediaQuery Shortcuts
52+
- `screenWidth` / `screenHeight` - Convenient aliases for screen dimensions
53+
- `padding` - Get safe area insets (notch, status bar, etc.)
54+
- `viewInsets` - Get system UI insets (keyboard, navigation bar, etc.)
55+
- `devicePixelRatio` - Get device pixel density
56+
57+
#### 🧭 BuildContext Extensions - Platform Detection
58+
- `isIOS` - Check if running on iOS platform
59+
- `isAndroid` - Check if running on Android platform
60+
- `isWeb` - Check if running on web platform (uses `kIsWeb` constant)
61+
62+
#### 🧭 BuildContext Extensions - Dialogs
63+
- `showCustomDialog(Widget dialog)` - Show Material dialog with less boilerplate
64+
- `showSheet(Widget content)` - Show modal bottom sheet with less boilerplate
65+
66+
#### 🔧 String Extensions
67+
- `toText({style})` - Convert String to Text widget
68+
- `toSelectableText({style})` - Convert String to SelectableText widget
69+
70+
#### 🔧 List<Widget> Extensions
71+
- `toColumn({mainAxisAlignment, mainAxisSize, crossAxisAlignment})` - Convert widget list to Column
72+
- `toRow({mainAxisAlignment, mainAxisSize, crossAxisAlignment})` - Convert widget list to Row
73+
- `toStack({alignment, fit})` - Convert widget list to Stack
74+
- `toWrap({alignment, runAlignment, spacing, runSpacing})` - Convert widget list to Wrap
75+
76+
#### 🎨 Color Extensions
77+
- `withOpacity(double opacity)` - Create color with specified opacity
78+
- `darken([double amount])` - Make color darker using HSL color space (default 10%)
79+
- `lighten([double amount])` - Make color lighter using HSL color space (default 10%)
80+
81+
#### 📐 EdgeInsets Extensions
82+
- `horizontal` - Get total horizontal padding (left + right)
83+
- `vertical` - Get total vertical padding (top + bottom)
84+
- `all` - Get uniform padding value (if all sides are equal)
85+
- `copyWith({left, top, right, bottom})` - Create modified copy of EdgeInsets
86+
1487
### Package Philosophy
1588

1689
This package is part of the **MayR Extensions** family:
@@ -80,7 +153,7 @@ If you were using the original `mayr_extensions` package:
80153
```dart
81154
// For general Dart extensions
82155
import 'package:mayr_dart_extensions/mayr_dart_extensions.dart';
83-
156+
84157
// For Flutter-specific extensions
85158
import 'package:mayr_flutter_extensions/mayr_flutter_extensions.dart';
86159
```

example/example.dart

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,198 @@ class ExampleScreen extends StatelessWidget {
126126
).clipRounded(16),
127127

128128
const SizedBox(height: 20),
129+
130+
/// New Widget Extensions - Sizing
131+
const Text(
132+
'Sizing Extensions',
133+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
134+
),
135+
const SizedBox(height: 10),
136+
137+
Container(
138+
color: Colors.orange,
139+
child: const Text('AspectRatio 16:9'),
140+
).aspectRatio(16 / 9),
141+
142+
const SizedBox(height: 10),
143+
144+
Container(
145+
color: Colors.teal,
146+
child: const Text('50% width'),
147+
).fractionallySizedBox(widthFactor: 0.5),
148+
149+
const SizedBox(height: 20),
150+
151+
/// New Widget Extensions - Styling
152+
const Text(
153+
'Styling Extensions',
154+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
155+
),
156+
const SizedBox(height: 10),
157+
158+
const Text('Decorated Box')
159+
.decorated(
160+
const BoxDecoration(
161+
color: Colors.lightBlue,
162+
borderRadius: BorderRadius.all(Radius.circular(8)),
163+
),
164+
)
165+
.paddingAll(16),
166+
167+
const SizedBox(height: 10),
168+
169+
const Text('Card Widget').card(elevation: 8.0).paddingAll(8),
170+
171+
const SizedBox(height: 10),
172+
173+
Container(height: 100, width: 100, color: Colors.green).clipOval(),
174+
175+
const SizedBox(height: 20),
176+
177+
/// New Widget Extensions - Layout
178+
const Text(
179+
'Layout Extensions',
180+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
181+
),
182+
const SizedBox(height: 10),
183+
184+
Container(
185+
height: 150,
186+
color: Colors.grey[300],
187+
child:
188+
Column(
189+
children: List.generate(
190+
20,
191+
(i) => Text('Scrollable Item $i'),
192+
),
193+
).scrollable(),
194+
),
195+
196+
const SizedBox(height: 10),
197+
198+
const Text('Safe Area Widget').safeArea(),
199+
200+
const SizedBox(height: 10),
201+
202+
Container(
203+
height: 100,
204+
width: 100,
205+
color: Colors.pink,
206+
child: const Text('FittedBox').fittedBox(fit: BoxFit.contain),
207+
),
208+
209+
const SizedBox(height: 20),
210+
211+
/// New Widget Extensions - Effects
212+
const Text(
213+
'Effects Extensions',
214+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
215+
),
216+
const SizedBox(height: 10),
217+
218+
const Text('Hero Tag').hero('demo-hero'),
219+
220+
const SizedBox(height: 10),
221+
222+
const Text('Rotated 1x').rotated(1),
223+
224+
const SizedBox(height: 20),
225+
226+
/// String Extensions
227+
const Text(
228+
'String Extensions',
229+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
230+
),
231+
const SizedBox(height: 10),
232+
233+
'String to Text Widget'.toText(
234+
style: const TextStyle(fontSize: 16, color: Colors.blue),
235+
),
236+
237+
const SizedBox(height: 10),
238+
239+
'Selectable Text Example'.toSelectableText(),
240+
241+
const SizedBox(height: 20),
242+
243+
/// List<Widget> Extensions
244+
const Text(
245+
'List<Widget> Extensions',
246+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
247+
),
248+
const SizedBox(height: 10),
249+
250+
[
251+
Container(color: Colors.red, height: 50, width: 50),
252+
Container(color: Colors.green, height: 50, width: 50),
253+
Container(color: Colors.blue, height: 50, width: 50),
254+
].toRow(mainAxisAlignment: MainAxisAlignment.spaceEvenly),
255+
256+
const SizedBox(height: 10),
257+
258+
[
259+
const Chip(label: Text('Chip 1')),
260+
const Chip(label: Text('Chip 2')),
261+
const Chip(label: Text('Chip 3')),
262+
].toWrap(spacing: 8),
263+
264+
const SizedBox(height: 20),
265+
266+
/// Color Extensions
267+
const Text(
268+
'Color Extensions',
269+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
270+
),
271+
const SizedBox(height: 10),
272+
273+
Row(
274+
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
275+
children: [
276+
Container(
277+
height: 50,
278+
width: 50,
279+
color: Colors.blue,
280+
child: const Center(child: Text('Original')),
281+
),
282+
Container(
283+
height: 50,
284+
width: 50,
285+
color: Colors.blue.darken(0.2),
286+
child: const Center(child: Text('Dark')),
287+
),
288+
Container(
289+
height: 50,
290+
width: 50,
291+
color: Colors.blue.lighten(0.2),
292+
child: const Center(child: Text('Light')),
293+
),
294+
],
295+
),
296+
297+
const SizedBox(height: 20),
298+
299+
/// Theme and Navigation Demo
300+
const Text(
301+
'Theme & Navigation Extensions',
302+
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
303+
),
304+
const SizedBox(height: 10),
305+
306+
Text('Primary Color: ${context.primaryColor}'),
307+
Text('Is Dark Mode: ${context.isDarkMode}'),
308+
Text('Screen Width: ${context.screenWidth}'),
309+
Text('Device Pixel Ratio: ${context.devicePixelRatio}'),
310+
311+
const SizedBox(height: 10),
312+
313+
ElevatedButton(
314+
onPressed: () {
315+
context.showSnackBar('Navigation extensions available!');
316+
},
317+
child: const Text('Test Navigation Extension'),
318+
),
319+
320+
const SizedBox(height: 20),
129321
],
130322
),
131323
),

lib/src/extensions.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import 'package:flutter/foundation.dart';
12
import 'package:flutter/material.dart';
23

34
import './extensions/utils/inkwell_manager.dart';
45

56
part './extensions/build_context.dart';
7+
part './extensions/color.dart';
8+
part './extensions/edge_insets.dart';
69
part './extensions/image_widget.dart';
710
part './extensions/stateless_widget.dart';
11+
part './extensions/string.dart';
812
part './extensions/text_style.dart';
913
part './extensions/text_widget.dart';
1014
part './extensions/widget.dart';
15+
part './extensions/widget_list.dart';

0 commit comments

Comments
 (0)