Skip to content

Commit

Permalink
fixed flutter bloc example
Browse files Browse the repository at this point in the history
updated deps
added extended bloc example with fetchMore and refetch
  • Loading branch information
vasilich6107 committed Apr 17, 2020
1 parent 4b71898 commit a924eb2
Show file tree
Hide file tree
Showing 14 changed files with 573 additions and 170 deletions.
4 changes: 3 additions & 1 deletion examples/flutter_bloc/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,6 @@
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages

lib/local.dart
lib/local.dart
/ios/Flutter/Flutter.podspec
/ios/Flutter/flutter_export_environment.sh
14 changes: 1 addition & 13 deletions examples/flutter_bloc/ios/Runner.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
Expand All @@ -28,8 +24,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
Expand All @@ -40,13 +34,11 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
Expand All @@ -60,8 +52,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -71,9 +61,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
Expand Down Expand Up @@ -206,7 +194,7 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
Expand Down
146 changes: 146 additions & 0 deletions examples/flutter_bloc/lib/bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';

import 'blocs/repos/events.dart';
import 'blocs/repos/models.dart';
import 'blocs/repos/my_repos_bloc.dart';
import 'blocs/repos/states.dart';

class BlocPage extends StatefulWidget {
@override
_BlocPageState createState() => _BlocPageState();
}

class _BlocPageState extends State<BlocPage> {
@override
void initState() {
super.initState();
final bloc = BlocProvider.of<MyGithubReposBloc>(context);
bloc.add(LoadMyRepos(numOfReposToLoad: 50));
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Flutter Bloc GraphQL Example"),
),
body: Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
TextField(
decoration: const InputDecoration(
labelText: 'Number of repositories (default 50)',
),
keyboardType: TextInputType.number,
textAlign: TextAlign.center,
onChanged: (String n) {
final reposBloc = BlocProvider.of<MyGithubReposBloc>(context);
reposBloc
.add(LoadMyRepos(numOfReposToLoad: int.parse(n) ?? 50));
},
),
SizedBox(
height: 10,
),
new LoadRepositories(
bloc: BlocProvider.of<MyGithubReposBloc>(context),
)
],
),
),
);
}
}

class LoadRepositories extends StatelessWidget {
final MyGithubReposBloc bloc;

const LoadRepositories({Key key, this.bloc}) : super(key: key);

@override
Widget build(BuildContext context) {
return BlocBuilder<MyGithubReposBloc, MyGithubReposState>(
bloc: bloc,
builder: (BuildContext context, MyGithubReposState state) {
if (state is ReposLoading) {
return Expanded(
child: Container(
child: Center(
child: CircularProgressIndicator(
semanticsLabel: "Loading ...",
),
),
),
);
}

if (state is ReposNotLoaded) {
return Text("${state.errors}");
}

if (state is ReposLoaded) {
final List<Repo> repositories = state.results;

return Expanded(
child: ListView.builder(
itemCount: state.results.length,
itemBuilder: (BuildContext context, int index) =>
StarrableRepository(
repository: repositories[index],
reposBloc: bloc,
),
),
);
}

return Text(null);
},
);
}
}

class StarrableRepository extends StatelessWidget {
const StarrableRepository({
Key key,
@required this.repository,
@required this.reposBloc,
}) : assert(reposBloc != null),
assert(repository != null),
super(key: key);

final Repo repository;
final MyGithubReposBloc reposBloc;

@override
Widget build(BuildContext context) {
return ListTile(
leading: _isRepoStarred(),
trailing: _showLoadingIndicator(),
title: Text(repository.name),
onTap: () {
reposBloc.add(MutateToggleStar(repo: repository));
},
);
}

Widget _showLoadingIndicator() {
if (repository.isLoading)
return CircularProgressIndicator();
else
return null;
}

Widget _isRepoStarred() {
if (repository.viewerHasStarred)
return Icon(
Icons.star,
color: Colors.amber,
);
else
return Icon(Icons.star_border);
}
}
12 changes: 6 additions & 6 deletions examples/flutter_bloc/lib/blocs/repos/my_repos_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:graphql/client.dart';
import 'package:graphql_flutter_bloc_example/blocs/repos/events.dart';
import 'package:graphql_flutter_bloc_example/blocs/repos/models.dart';
Expand Down Expand Up @@ -32,7 +32,7 @@ class MyGithubReposBloc extends Bloc<MyGithubReposEvent, MyGithubReposState> {
}
} catch (_, stackTrace) {
print('$_ $stackTrace');
yield currentState;
yield state;
}
}

Expand All @@ -43,8 +43,8 @@ class MyGithubReposBloc extends Bloc<MyGithubReposEvent, MyGithubReposState> {
final queryResults =
await this.githubRepository.getRepositories(numOfRepositories);

if (queryResults.hasErrors) {
yield ReposNotLoaded(queryResults.errors);
if (queryResults.hasException) {
yield ReposNotLoaded(queryResults.exception.graphqlErrors);
return;
}

Expand Down Expand Up @@ -101,9 +101,9 @@ class MyGithubReposBloc extends Bloc<MyGithubReposEvent, MyGithubReposState> {

final queryResults = await githubRepository.toggleRepoStar(repo);

if (queryResults.hasErrors) {
if (queryResults.hasException) {
// @TODO Improve error handling here, may be introduce a hasError Method
yield ReposNotLoaded(queryResults.errors);
yield ReposNotLoaded(queryResults.exception.graphqlErrors);
return;
}

Expand Down
75 changes: 75 additions & 0 deletions examples/flutter_bloc/lib/extended-bloc/graphql/bloc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'dart:async';
import 'package:bloc/bloc.dart';
import 'package:graphql/client.dart';
import 'package:meta/meta.dart';
import 'package:graphql/internal.dart';

import 'event.dart';
import 'state.dart';

abstract class GraphqlBloc<T> extends Bloc<GraphqlEvent<T>, GraphqlState<T>> {
GraphQLClient client;
ObservableQuery result;
WatchQueryOptions options;

GraphqlBloc({this.client, @required this.options}) {
result = client.watchQuery(options);

result.stream.listen((QueryResult result) {
if (!result.loading && result.data != null) {
add(
GraphqlLoadedEvent<T>(
data: parseData(result.data as Map<String, dynamic>),
result: result,
),
);
}

if (result.hasException) {
add(GraphqlErrorEvent(error: result.exception, result: result));
}
});

_runQuery();
}

void dispose() {
result.close();
}

T parseData(Map<String, dynamic> data);

Future<void> _runQuery() async {
result.fetchResults();
}

void _fetchMore(FetchMoreOptions options) {
result.fetchMore(options);
}

void _refetch() => result.refetch();

@override
GraphqlState<T> get initialState => GraphqlLoading<T>();

@override
Stream<GraphqlState<T>> mapEventToState(GraphqlEvent<T> event) async* {
if (event is GraphqlLoadedEvent<T>) {
yield GraphqlLoaded<T>(data: event.data, result: event.result);
}

if (event is GraphqlErrorEvent<T>) {
yield GraphqlErrorState<T>(error: event.error, result: event.result);
}

if (event is GraphqlRefetchEvent<T>) {
yield GraphqlRefetchState<T>(data: state.data, result: null);
_refetch();
}

if (state is GraphqlLoaded && event is GraphqlFetchMoreEvent<T>) {
yield GraphqlFetchMoreState<T>(data: state.data, result: null);
_fetchMore(event.options);
}
}
}
26 changes: 26 additions & 0 deletions examples/flutter_bloc/lib/extended-bloc/graphql/event.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:graphql/client.dart';
import 'package:meta/meta.dart';

abstract class GraphqlEvent<T> {}

class GraphqlErrorEvent<T> extends GraphqlEvent<T> {
final OperationException error;
final QueryResult result;

GraphqlErrorEvent({@required this.error, @required this.result});
}

class GraphqlLoadedEvent<T> extends GraphqlEvent<T> {
final T data;
final QueryResult result;

GraphqlLoadedEvent({@required this.data, @required this.result});
}

class GraphqlRefetchEvent<T> extends GraphqlEvent<T> {}

class GraphqlFetchMoreEvent<T> extends GraphqlEvent<T> {
final FetchMoreOptions options;

GraphqlFetchMoreEvent({@required this.options});
}
Loading

0 comments on commit a924eb2

Please sign in to comment.