Skip to content

Commit 3614eb6

Browse files
committed
Release of first stable version - 1.0.0
1 parent 20ef041 commit 3614eb6

File tree

451 files changed

+9316
-811
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

451 files changed

+9316
-811
lines changed

.vscode/launch.json

+11-17
Original file line numberDiff line numberDiff line change
@@ -2,46 +2,40 @@
22
"version": "0.3.0",
33
"configurations": [
44
{
5-
"name": "Common Layout | Inherited Widget",
5+
"name": "Common Layout",
66
"type": "dart",
77
"request": "launch",
8-
"program": "example/lib/common_layout/inherited_widget.dart",
9-
},
10-
{
11-
"name": "Common Layout | Override Inherited Widget",
12-
"type": "dart",
13-
"request": "launch",
14-
"program": "example/lib/common_layout/override_inherited_widget.dart",
8+
"program": "example/common_layout/lib/main.dart",
159
},
1610
{
1711
"name": "Custom Layout",
1812
"type": "dart",
1913
"request": "launch",
20-
"program": "example/lib/custom_layout/main.dart",
14+
"program": "example/custom_layout/lib/main.dart",
2115
},
2216
{
23-
"name": "Granular Layout | Override Inherited Widget",
17+
"name": "Granular Layout",
2418
"type": "dart",
2519
"request": "launch",
26-
"program": "example/lib/granular_layout/override_inherited_widget.dart",
20+
"program": "example/granular_layout/lib/main.dart",
2721
},
2822
{
29-
"name": "Granular Layout | Override Inherited Widget",
23+
"name": "Provider Usage",
3024
"type": "dart",
3125
"request": "launch",
32-
"program": "example/lib/granular_layout/override_inherited_widget.dart",
26+
"program": "example/provider_usage/lib/main.dart",
3327
},
3428
{
35-
"name": "Provider",
29+
"name": "Riverpod Usage",
3630
"type": "dart",
3731
"request": "launch",
38-
"program": "example/lib/provider.dart",
32+
"program": "example/river_pod_usage/lib/main.dart",
3933
},
4034
{
41-
"name": "Riverpod",
35+
"name": "Split View",
4236
"type": "dart",
4337
"request": "launch",
44-
"program": "example/lib/river_pod.dart",
38+
"program": "example/split_view/lib/main.dart",
4539
},
4640
]
4741
}

CHANGELOG.md

+34-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,37 @@
1-
## [1.0.0-nullsafety.0]
1+
## 1.0.0
2+
3+
First stable release containing the `Spacing` utilities and a couple of minor improvements.
4+
5+
## Breaking Changes
6+
7+
- `CommonLayout` and `GranularLayout` `value` function now requires the type `T` to extend from `Object`, not allowing
8+
the return of `null` values (which threw a `null` access in specific scenarios). This was intended but the
9+
type-inference allowed nullable types when not enforced by `Object`;
10+
- `CommonLayoutWidget`/`GranularLayoutWidget` constructors requires a `resolverBuilder` instead of a `resolver`.
11+
12+
#### Added
13+
- Unit and Widget tests for all the features provided in `layoutr`;
14+
- `maybeValue` in both `CommonLayout` and `GranularLayout`;
15+
- `Spacing`, `RawSpacings` and `SpacingsInheritedWidget` with utilities (`SpacingMixin`, `SpacingHelpers` and
16+
`SpacingPaddingHelpers`);
17+
- `LayoutResolverInheritedWidget`, base `InheritedWidget` for all `LayoutResolver` implementations;
18+
- Both `CommonLayoutWidget`/`GranularLayoutWidget`:
19+
- accept a new optional `spacings` argument that allows responsive and type-safe spacing alongside the usual resolver;
20+
- `withResponsiveSpacings` for a fine-grained constructor of breakpoint-specific `spacings`.
21+
- `split_view` example.
22+
23+
#### Updated
24+
- Both `CommonLayoutWidget`/`GranularLayoutWidget` can live independent from a `MediaQuery` parent widget (by using a
25+
`LayoutBuilder`);
26+
- Restructured the example folder to a more realistic usage (also added a ton of comments to the respective examples);
27+
- `README.md` to reflect the new `Spacing` features.
28+
29+
### Fixed
30+
31+
- `LayoutResolver.closestValue` now throws a descriptive `ArgumentError` for empty dictionaries;
32+
33+
34+
## 1.0.0-nullsafety.0
235

336
First library release, everything already documented in `README.md`.
437

CONTRIBUTING.md

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
There is no rocket science to contributing to this project. Just open your issue or pull request if needed - but please be descriptive!
2+
3+
To submit a PR, follow [these useful guidelines](https://gist.github.com/MarcDiethelm/7303312), respect the dartfmt lint (modifications/exceptions may be discussed), and create an awesome description so we can understand it.
4+
5+
Even though there is no "rules" to how you should contribute, there goes my quick tips on it:
6+
7+
- If you're experiencing a bug that can be demonstrated visually, please take screenshots and post them alongside the issue;
8+
- For a quicker/seamless understanding of the issue, please post a sample project, so the evaluation will be bulletproof;
9+
- This is a git overall tip - do atomic commits with a descriptive message (no more than 50 characters is ideal).

README.md

+154-38
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,23 @@ Even though the magic should happen inside the abstract `LayoutResolver`, we nee
2323
But that's not any reason to not have built-in Layout Resolvers, and these will probably fit the most generic use-cases. To exemplify the resolvers, we can see how the `CommonLayout` works.
2424

2525
#### Exemplifying with CommonLayout
26+
---
27+
28+
Before diving into the concepts, you have to make sure to provide a `CommonLayout` for your widgets. This can be done
29+
in multiple different ways, although the easiest is to just wrap your top-most widget in the `CommonLayoutWidget`:
30+
31+
```dart
32+
import 'package:layoutr/common_layout.dart';
33+
34+
// ...
35+
CommonLayoutWidget(
36+
child: /* My child, possibly a MaterialApp/WidgetsApp */,
37+
);
38+
// ...
39+
```
40+
41+
Now, `CommonLayout` is split in 4 breakpoints: `desktop`, `tablet`, `phone` and `tinyHardware`. A simple usage of returning a responsive `Text` widget that has both its value and style customized based on the current device's constraints may be done like the below:
2642

27-
The `CommonLayout` is split in 4 breakpoints: `desktop`, `tablet`, `phone` and `tinyHardware`. A simple usage of returning a responsive `Text` widget that has both its value and style customized based on the current device's constraints may be done like the below:
2843
```dart
2944
import 'package:layoutr/common_layout.dart';
3045
@@ -43,23 +58,9 @@ Widget build(BuildContext context) {
4358
// ...
4459
```
4560

46-
> You can see that there is no `tablet` supplied to the `layout.value`, and that is intended to exemplify a common scenario, where we may want to just provide two or three arguments - and that means not all possible scenarios are "covered" - and that's where the resolver comes in handy: if the **current breakpoint** value is not passed to `layout.value`, it will fallback to the "nearest" available one, fitting the most suitable layout for your particular value. This "nearest logic" can be confusing, but you can find out more how it works in `LayoutResolver.closestValue`
47-
48-
Also, if you want to keep the structure but want to override the sizes of each breakpoint, you can provide your `CommonLayout` instance through the InheritedWidget called `CommonLayoutWidget`:
49-
50-
```dart
51-
import 'package:layoutr/common_layout.dart';
52-
53-
// ...
54-
55-
CommonLayoutWidget(
56-
resolver: CommonLayout(context.deviceWidth, desktop: 800),
57-
child: /* My child */,
58-
);
59-
// ...
60-
```
61-
62-
> You will probably want to add these above the top-most widget of your tree, usually the `MaterialApp`, but be careful that `MediaQuery` may not be available if you don't have any other widget above `CommonLayoutWidget`, which is required when we use the `context.deviceWidth`. You can check out an [`example/`](https://pub.dev/packages/layoutr/example#Common-Layout-Inherited-Widget) that overrides the custom values.
61+
> **TLDR: all breakpoints don't need to be provided, the layout will automatically find the nearest suitable value for your current breakpoint.**
62+
>
63+
> Long version: you can see that there is no `tablet` supplied to the `layout.value`, and that is intended to exemplify a common scenario, where we may want to just provide two or three arguments - and that means not all possible scenarios are "covered" - and that's where the resolver comes in handy: if the **current breakpoint** value is not passed to `layout.value`, it will fallback to the "nearest" available one, fitting the most suitable layout for your particular value. This "nearest logic" can be confusing, but you can find out more how it works in `LayoutResolver.closestValue`
6364
6465
Other than `layout.value`, the `CommonLayout` provide utilities for simple boolean comparisons:
6566

@@ -82,10 +83,7 @@ Widget build(BuildContext context) {
8283
children: [
8384
// And we wan't to have a custom title `AppBar` if the current layout is a tablet or smaller
8485
if (layout.isDesktop)
85-
Padding(
86-
padding: const EdgeInsets.only(bottom: 40),
87-
child: Text(pageTitle, style: Theme.of(context).textTheme.headline3),
88-
),
86+
Text(pageTitle, style: Theme.of(context).textTheme.headline3),
8987
// ... the rest of the widget
9088
],
9189
),
@@ -95,20 +93,146 @@ Widget build(BuildContext context) {
9593
// ...
9694
```
9795

98-
Tip: we can easily use this package with common libraries like `provider` (see in [`example/`](https://pub.dev/packages/layoutr/example#`provider`)) and `river_pod` (see in [`example/`](https://pub.dev/packages/layoutr/example#`river_pod`)).
96+
##### Overriding `CommonLayout` resolver
97+
---
98+
99+
To override the sizes for each breakpoint, you can provide your own `CommonLayout` instance:
100+
101+
```dart
102+
import 'package:layoutr/common_layout.dart';
103+
// ...
104+
CommonLayoutWidget(
105+
resolverBuilder: (constraints) => CommonLayout(constraints.maxWidth, desktop: 800, tablet: 520),
106+
child: /* My child */,
107+
);
108+
// ...
109+
```
110+
111+
> **TLDR: your app don't need to necessarily use `MaterialApp` (or `WidgetsApp`), just add it above your top-most widget.**
112+
>
113+
> Long version: it's probably the best to add the resolver widget above the top-most widget of your tree, because the all built-in widgets use a `LayoutBuilder` to provide such responsive features, and this may create inconsistencies if they are created in nested widgets, which will only use the parent's `BoxConstraints`. This could also be useful if you wanted to created a resolver that is not necessarily related to the device's sizes, but I fail to see a useful scenario like this at the moment.
114+
115+
##### Overriding `CommonLayout` spacings
116+
---
117+
To override the spacings for each breakpoint, you can provide your own `RawSpacings` instance:
118+
119+
```dart
120+
import 'package:layoutr/common_layout.dart';
121+
// ...
122+
CommonLayoutWidget(
123+
spacings: const RawSpacings(4, 12, 20, 24, 32, 40, 48, 56, 60),
124+
child: /* My child */,
125+
);
126+
// ...
127+
```
128+
129+
While the above will customize all spacings for all breakpoints, it's still not responsive, and that's fine. You may
130+
want to use the spacings for the sole benefit of type-safety utilities. Now if you also want them to be responsive,
131+
there is a constructor for that:
132+
133+
```dart
134+
import 'package:layoutr/common_layout.dart';
135+
136+
// ...
137+
CommonLayoutWidget.withResponsiveSpacings(
138+
desktopSpacings: RawSpacings(8, 16, 24, 32, 40, 52, 60, 68, 80),
139+
phoneSpacings: RawSpacings(4, 8, 12, 20, 28, 36, 40, 48, 60),
140+
child: /* My child */,
141+
);
142+
// ...
143+
```
144+
145+
Not sure what spacings mean? Check out [spacings](#spacings).
146+
147+
----
148+
Tips:
149+
- we can easily use this package with common libraries like `provider` (see in [`example/`](example/provider_usage/)) and `river_pod` (see in [`example/`](example/river_pod_usage/`));
150+
- everything explained here is same for all built-in resolvers (like `GranularLayout`), they just differ in the
151+
breakpoints amount/types.
99152

100153
#### Available Built-in `LayoutResolver`
101-
- `CommonLayout`: a resolver split in 4 breakpoints: `desktop`, `tablet`, `phone` and `tinyHardware`. Import this resolver through `package:layoutr/common_layout.dart` - (see in [`example/`](https://pub.dev/packages/layoutr/example#Common-Layout));
102-
- `GranularLayout`: a resolver split in 6 breakpoints: `xxLarge`, `xLarge`, `large`, `medium`, `small` and `xSmall`. Import this resolver through `package:layoutr/granular_layout.dart` - (see in [`example/`](https://pub.dev/packages/layoutr/example#Granular-Layout)).
154+
---
155+
156+
- `CommonLayout`: a resolver split in 4 breakpoints: `desktop`, `tablet`, `phone` and `tinyHardware`. Import this resolver through `package:layoutr/common_layout.dart` - (see in [`example/`](example/common_layout/));
157+
- `GranularLayout`: a resolver split in 6 breakpoints: `xxLarge`, `xLarge`, `large`, `medium`, `small` and `xSmall`. Import this resolver through `package:layoutr/granular_layout.dart` - (see in [`example/`](example/granular_layout/)).
158+
159+
#### Custom `LayoutResolver`
160+
---
161+
162+
If the above built-in resolvers don't match the requirements, `LayoutResolver` can be customized by extending it, taking advantage of the utilities built-in in the abstract class itself. To extend the and implement your custom `LayoutResolver`, import `package:layoutr/layoutr.dart`. Check out a custom implementation example in the [`example/`](example/custom_layout/).
163+
164+
### Spacings
165+
166+
All spacing features revolve around `Spacing` enumerator. These are named ranges that should usually fit most use-cases
167+
out there in the wild. They are pretty intuitive: `xxxSmall`, `xxSmall`, `xSmall`, `small`, `medium`, ... and so on.
103168

104-
### Custom `LayoutResolver`
169+
Spacings are an additional help for situations where we need type-safety, responsivity, or both. Being more specific:
170+
- type-safety: even if you don't want to use it as a responsive value, you will still benefit from having a type-safe
171+
system that will prevent inconsistent spacings, margins and paddings in your application;
172+
- responsivity: the spacings can be customized to one, some or all breakpoints, meaning that you won't have to change
173+
anything if you use the `Spacing` type system.
105174

106-
If the above built-in resolvers don't match the requirements, `LayoutResolver` can be customized by extending it, taking advantage of the utilities built-in in the abstract class itself. To extend the and implement your custom `LayoutResolver`, import `package:layoutr/layoutr.dart`. Check out a custom implementation example in the [`example/`](https://pub.dev/packages/layoutr/example#Custom-Layout).
175+
All built-in `LayoutResolver` will provide the spacings out-of-the-box, so no need to add anything extra other than your root widget. But this might not be the best for most. If wanted, one could use only this package's feature alone (with `SpacingsInheritedWidget`), like so:
176+
177+
```dart
178+
import 'package:layoutr/layoutr.dart';
179+
180+
// ...
181+
LayoutBuilder(
182+
builder: (context, constraints) {
183+
// If we wanted, we could use this spacings type-safety/responsivity without the resolver themselves
184+
final myCustomSpacings = constraints.maxWidth > 800
185+
? RawSpacings(16, 24, 32, 40, 52, 60, 68, 76, 80)
186+
: RawSpacings(8, 12, 24, 32, 40, 48, 56, 64, 72);
187+
188+
return SpacingsInheritedWidget(
189+
spacings: myCustomSpacings,
190+
child: // ... ,
191+
);
192+
},
193+
);
194+
// ...
195+
```
196+
197+
Alone this can be somewhat useful, but its potential is enhanced with the built-in utilities and resolvers
198+
widgets - you can even build your own by extending any `BuildContext`, `Widget` or any layout-related element.
199+
200+
An example usage with some of the utilities:
201+
202+
```dart
203+
import 'package:layoutr/layoutr.dart';
204+
205+
// SpacingMixin just helps you to call spacings like `smallSpacing`, instead of `Spacing.smallSpacing`, making it
206+
// overall less verbose.
207+
class MyPage extends StatelessWidget with SpacingMixin {
208+
@override
209+
Widget build(BuildContext context) {
210+
return Scaffold(
211+
body: Column(
212+
children: [
213+
Text('My page'),
214+
// Creates a vertical responsive/type-safe spacing
215+
context.verticalBox(xxxLargeSpacing),
216+
Container(
217+
// Creates a vertical symmetrical insets responsive/type-safe spacing
218+
margin: context.symmetricInsets(vertical: smallSpacing),
219+
color: Colors.amber,
220+
// Wraps this widget in a Padding with all insets to this responsive/type-safe spacing
221+
child: Placeholder().withAllPadding(context, mediumSpacing),
222+
),
223+
],
224+
),
225+
);
226+
}
227+
}
228+
```
107229

108230
### Utilities
109231

110-
- Syntax-sugar for common use-cases, like: `deviceWidth` and `deviceHeight` (plus a couple more that are WIP);
111-
- Other helper Widgets are WIP.
232+
- Syntax-sugar for common use-cases, like: `deviceWidth` and `deviceHeight`;
233+
- [Helpers] for commonly used elements like `EdgeInsets` and `Padding`, using `Spacing`.
234+
235+
Check out all [spacing utilities](lib/src/utilities.dart).
112236

113237
## Reference OS Projects
114238

@@ -118,12 +242,4 @@ WIP
118242

119243
## Contributing
120244

121-
There is no rocket science to contributing to this project. Just open your issue or pull request if needed - but please be descriptive!
122-
123-
To submit a PR, follow [these useful guidelines](https://gist.github.com/MarcDiethelm/7303312), respect the dartfmt lint (modifications/exceptions may be discussed), and create an awesome description so we can understand it.
124-
125-
Even though there is no "rules" to how you should contribute, there goes my quick tips on it:
126-
127-
- If you're experiencing a bug that can be demonstrated visually, please take screenshots and post them alongside the issue;
128-
- For a quicker/seamless understanding of the issue, please post a sample project, so the evaluation will be bulletproof;
129-
- This is a git overall tip - do atomic commits with a descriptive message (no more than 50 characters is ideal).
245+
Want to contribute? Check it out [here](CONTRIBUTING.md).

0 commit comments

Comments
 (0)