Skip to content

Commit

Permalink
Merge pull request #24 from zino-app/providers-1
Browse files Browse the repository at this point in the history
`GraphqlProvider` and `GraphqlConsumer` widgets
  • Loading branch information
HofmannZ authored Jul 20, 2018
2 parents 6e6aff7 + 713f902 commit cfb027b
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 84 deletions.
71 changes: 59 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@

- [Installation](#installation)
- [Usage](#usage)
- [Graphql Provider](#graphql-provider)
- [Queries](#queries)
- [Mutations](#mutations)
- [Graphql Consumer](#graphql-consumer)
- [Offline Cache](#offline-cache)
- [Roadmap](#roadmap)
- [Contributing](#contributing)
Expand All @@ -36,7 +38,7 @@ import 'package:graphql_flutter/graphql_flutter.dart';

## Usage

To use the client it first needs to be initialized with an endpoint and cache. If your endpoint requires authentication you can provide it to the client by calling the setter `apiToken` on the `Client` class.
To use the client it first needs to be initialized with an endpoint and cache. If your endpoint requires authentication you can provide it to the client contructor. If you need to change the api token at a later stage, you can call the setter `apiToken` on the `Client` class.

> For this example we will use the public GitHub API.
Expand All @@ -45,19 +47,39 @@ To use the client it first needs to be initialized with an endpoint and cache. I
import 'package:graphql_flutter/graphql_flutter.dart';
void main() async {
client = new Client(
endPoint: 'https://api.github.com/graphql',
cache: new InMemoryCache(), // currently the only cache type we have implemented.
void main() {
ValueNotifier<Client> client = new ValueNotifier(
new Client(
endPoint: 'https://api.github.com/graphql',
cache: new InMemoryCache(),
apiToken: '<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>',
),
);
client.apiToken = '<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>';
...
}
...
```

### Graphql Provider

In order to use the client, you app needs to be wrapped with the `GraphqlProvider` widget.

```dart
...
return new GraphqlProvider(
client: client,
child: new MaterialApp(
title: 'Flutter Demo',
...
),
);
...
```

### Queries

Creating a query is as simple as creating a multiline string:
Expand Down Expand Up @@ -179,23 +201,45 @@ new Mutation(
...
```

### Graphql Consumer

You can always access the client direcly from the `GraphqlProvider` but to make it even easier you can also use the `GraphqlConsumer` widget.

```dart
...
return new GraphqlConsumer(
builder: (Client client) {
// do something with the client
return new Container(
child: new Text('Hello world'),
);
},
);
...
```

### Offline Cache

The in-memory cache can automatically be saved to and restored from offline storage. Setting it up is as easy as wrapping your app with the `CacheProvider` widget.

> Make sure the `CacheProvider` widget is inside the `GraphqlProvider` widget.
```dart
...
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new CacheProvider(
child: new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
return new GraphqlProvider(
client: client,
child: new CacheProvider(
child: new MaterialApp(
title: 'Flutter Demo',
...
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
Expand All @@ -212,8 +256,10 @@ This is currently our roadmap, please feel free to request additions/changes.
| :---------------------- | :------: |
| Basic queries ||
| Basic mutations ||
| Basic subscriptions | 🔜 |
| Query variables ||
| Mutation variables ||
| Subscription variables | 🔜 |
| Query polling ||
| In memory caching ||
| Offline caching ||
Expand All @@ -232,6 +278,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
<!-- prettier-ignore -->
| [<img src="https://avatars2.githubusercontent.com/u/4757453?v=4" width="100px;"/><br /><sub><b>Eustatiu Dima</b></sub>](http://eusdima.com)<br />[🐛](https://github.com/zino-app/graphql-flutter/issues?q=author%3Aeusdima "Bug reports") [💻](https://github.com/zino-app/graphql-flutter/commits?author=eusdima "Code") [📖](https://github.com/zino-app/graphql-flutter/commits?author=eusdima "Documentation") [💡](#example-eusdima "Examples") [🤔](#ideas-eusdima "Ideas, Planning, & Feedback") [👀](#review-eusdima "Reviewed Pull Requests") | [<img src="https://avatars3.githubusercontent.com/u/17142193?v=4" width="100px;"/><br /><sub><b>Zino Hofmann</b></sub>](https://github.com/HofmannZ)<br />[🐛](https://github.com/zino-app/graphql-flutter/issues?q=author%3AHofmannZ "Bug reports") [💻](https://github.com/zino-app/graphql-flutter/commits?author=HofmannZ "Code") [📖](https://github.com/zino-app/graphql-flutter/commits?author=HofmannZ "Documentation") [💡](#example-HofmannZ "Examples") [🤔](#ideas-HofmannZ "Ideas, Planning, & Feedback") [🚇](#infra-HofmannZ "Infrastructure (Hosting, Build-Tools, etc)") [👀](#review-HofmannZ "Reviewed Pull Requests") | [<img src="https://avatars2.githubusercontent.com/u/15068096?v=4" width="100px;"/><br /><sub><b>Harkirat Saluja</b></sub>](https://github.com/jinxac)<br />[📖](https://github.com/zino-app/graphql-flutter/commits?author=jinxac "Documentation") [🤔](#ideas-jinxac "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/5178217?v=4" width="100px;"/><br /><sub><b>Chris Muthig</b></sub>](https://github.com/camuthig)<br />[💻](https://github.com/zino-app/graphql-flutter/commits?author=camuthig "Code") [📖](https://github.com/zino-app/graphql-flutter/commits?author=camuthig "Documentation") [💡](#example-camuthig "Examples") [🤔](#ideas-camuthig "Ideas, Planning, & Feedback") | [<img src="https://avatars1.githubusercontent.com/u/7611406?v=4" width="100px;"/><br /><sub><b>Cal Pratt</b></sub>](http://stackoverflow.com/users/3280538/flkes)<br />[🐛](https://github.com/zino-app/graphql-flutter/issues?q=author%3Acal-pratt "Bug reports") [💻](https://github.com/zino-app/graphql-flutter/commits?author=cal-pratt "Code") [📖](https://github.com/zino-app/graphql-flutter/commits?author=cal-pratt "Documentation") [💡](#example-cal-pratt "Examples") [🤔](#ideas-cal-pratt "Ideas, Planning, & Feedback") |
| :---: | :---: | :---: | :---: | :---: |

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind are welcome!
Expand Down
37 changes: 20 additions & 17 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,29 @@ import 'package:graphql_flutter/graphql_flutter.dart';
import './queries/readRepositories.dart' as queries;
import './mutations/addStar.dart' as mutations;

void main() {
client = new Client(
endPoint: 'https://api.github.com/graphql',
cache: new InMemoryCache(),
);
client.apiToken = '<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>';

runApp(new MyApp());
}
void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new CacheProvider(
child: new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
ValueNotifier<Client> client = new ValueNotifier(
new Client(
endPoint: 'https://api.github.com/graphql',
cache: new InMemoryCache(),
apiToken: '<YOUR_GITHUB_PERSONAL_ACCESS_TOKEN>',
),
);

return new GraphqlProvider(
client: client,
child: new CacheProvider(
child: new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
Expand Down Expand Up @@ -82,7 +85,7 @@ class _MyHomePageState extends State<MyHomePage> {
}) {
if (data.isNotEmpty) {
repository['viewerHasStarred'] =
data['addStar']['starrable']['viewerHasStarred'];
data['addStar']['starrable']['viewerHasStarred'];
}

return new ListTile(
Expand Down Expand Up @@ -113,7 +116,7 @@ class _MyHomePageState extends State<MyHomePage> {
)
],
);
}
},
);
},
);
Expand Down
3 changes: 2 additions & 1 deletion lib/graphql_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export 'package:graphql_flutter/src/client.dart';

export 'package:graphql_flutter/src/cache/in_memory.dart';

export 'package:graphql_flutter/src/widgets/graphql_provider.dart';
export 'package:graphql_flutter/src/widgets/cache_provider.dart';
export 'package:graphql_flutter/src/widgets/query.dart';
export 'package:graphql_flutter/src/widgets/mutation.dart';
export 'package:graphql_flutter/src/widgets/cache_provider.dart';
8 changes: 5 additions & 3 deletions lib/src/client.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,18 @@ import 'package:http/http.dart' as http;

import 'package:graphql_flutter/src/cache/in_memory.dart';

Client client;

class Client {
Client({
String endPoint = '',
InMemoryCache cache,
String apiToken,
}) {
assert(endPoint != null);
assert(cache != null);

this.endPoint = endPoint;
this.cache = cache;

this.apiToken = apiToken;
this.client = new http.Client();
}

Expand Down
27 changes: 19 additions & 8 deletions lib/src/widgets/cache_provider.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';

import 'package:graphql_flutter/src/client.dart';
import 'package:graphql_flutter/src/widgets/graphql_provider.dart';

class CacheProvider extends StatefulWidget {
const CacheProvider({
Expand All @@ -20,11 +21,19 @@ class _CacheProviderState extends State<CacheProvider>
void initState() {
super.initState();

client.cache.restore();

WidgetsBinding.instance.addObserver(this);
}

@override
void didChangeDependencies() {
Client client = GraphqlProvider.of(context).value;
assert(client != null);

client.cache?.restore();

super.didChangeDependencies();
}

@override
void dispose() {
super.dispose();
Expand All @@ -34,26 +43,28 @@ class _CacheProviderState extends State<CacheProvider>

@override
void didChangeAppLifecycleState(AppLifecycleState state) {
/// Gets the client from the closest wrapping [GraphqlProvider].
Client client = GraphqlProvider.of(context).value;
assert(client != null);

switch (state) {
case AppLifecycleState.inactive:
client.cache.save();
client.cache?.save();
break;

case AppLifecycleState.paused:
client.cache.save();
client.cache?.save();
break;

case AppLifecycleState.suspending:
break;

case AppLifecycleState.resumed:
client.cache.restore();
client.cache?.restore();
break;
}
}

@override
Widget build(BuildContext context) {
return widget.child;
}
Widget build(BuildContext context) => widget.child;
}
23 changes: 23 additions & 0 deletions lib/src/widgets/graphql_consumer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:flutter/widgets.dart';

import 'package:graphql_flutter/src/client.dart';
import 'package:graphql_flutter/src/widgets/graphql_provider.dart';

typedef Widget GraphqlConsumerBuilder(Client client);

class GraphqlConsumer extends StatelessWidget {
GraphqlConsumer({
final Key key,
@required this.builder,
}) : super(key: key);

final GraphqlConsumerBuilder builder;

Widget build(BuildContext context) {
/// Gets the client from the closest wrapping [GraphqlProvider].
Client client = GraphqlProvider.of(context).value;
assert(client != null);

return builder(client);
}
}
66 changes: 66 additions & 0 deletions lib/src/widgets/graphql_provider.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'package:flutter/widgets.dart';

import 'package:graphql_flutter/src/client.dart';

class GraphqlProvider extends StatefulWidget {
const GraphqlProvider({
Key key,
this.client,
this.child,
}) : super(key: key);

final ValueNotifier<Client> client;
final Widget child;

static ValueNotifier<Client> of(BuildContext context) {
_InheritedGraphqlProvider inheritedGraphqlProvider =
context.inheritFromWidgetOfExactType(_InheritedGraphqlProvider);

return inheritedGraphqlProvider.client;
}

@override
State<StatefulWidget> createState() => new _GraphqlProviderState();
}

class _GraphqlProviderState extends State<GraphqlProvider> {
void didValueChange() => setState(() {});

@override
initState() {
super.initState();

widget.client.addListener(didValueChange);
}

@override
dispose() {
widget.client?.removeListener(didValueChange);

super.dispose();
}

@override
Widget build(BuildContext context) {
return new _InheritedGraphqlProvider(
client: widget.client,
child: widget.child,
);
}
}

class _InheritedGraphqlProvider extends InheritedWidget {
_InheritedGraphqlProvider({
this.client,
this.child,
}) : clientValue = client.value;

final ValueNotifier<Client> client;
final Widget child;
final Client clientValue;

@override
bool updateShouldNotify(_InheritedGraphqlProvider oldWidget) {
return clientValue != oldWidget.clientValue;
}
}
Loading

0 comments on commit cfb027b

Please # to comment.