Relation
This package is part of the SurfGear toolkit made by Surf.
About
The stream representation of the relations of the entities and widget utilities
Usage
Main classes:
- StreamedAction 1.1 ScrollOffsetAction 1.2 TextEditingAction
- Builder 2.1 EntityStateBuilder 2.2 StreamedStateBuilder 2.3 TextfieldStateBuilder
- StreamedState
- EntityStreamedState
Actions
StreamedAction
It's wrapper over an action on screen. It may be a tap on button, text changes, focus changes and so on.
SomeWidget(
onTap: someAction.accept,
)
...
someAction.action.listen(doSomething);
ScrollOffsetAction
The action that fires when the value changes when scrolling.
testWidgets(
'ScrollOffsetAction test',
(WidgetTester tester) async {
final action = ScrollOffsetStreamedAction((onChanged) {
expect(1.0, onChanged);
});
await tester.pumpWidget(MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
appBar: AppBar(
title: Text('test'),
),
body: ListView(
controller: action.controller,
scrollDirection: Axis.vertical,
children: <Widget>[
Text('test'),
Text('test'),
Text('test'),
],
),
),
));
action.controller.jumpTo(1.0);
},
);
TextEditingStreamedAction
Currently experimental.
An action that fires when a text field receives new characters
test('TextEditingAction test', () {
final action = TextEditingAction((onChanged) {
expect('test', onChanged);
});
action.controller.text = 'test';
});
Builder
Builders are widgets that listen to a change in a stream and provide new data to child widgets
StreamedStateBuilder
Updates child widget when an answer arrives
testWidgets(
'StreamedStateBuilder test',
(WidgetTester tester) async {
final testData = StreamedState<String>('test');
final streamedStateBuilder = StreamedStateBuilder<String>(
streamedState: testData,
builder: (context, data) {
return Text(data);
});
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: streamedStateBuilder,
),
),
);
final textFinder = find.text('test');
expect(textFinder, findsOneWidget);
},
);
EntityStateBuilder
This builder has three states onResponse, onError, onLoading
testWidgets(
'StreamedStateBuilder accept test',
(WidgetTester tester) async {
final testData = EntityStreamedState<String>(EntityState(data: 'test'));
final streamedStateBuilder = EntityStateBuilder<String>(
streamedState: testData,
child: (context, data) {
return Text(data);
},
);
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: streamedStateBuilder,
),
),
);
expect(streamedStateBuilder.streamedState.value.data, 'test');
final testFinder = find.text('test');
expect(testFinder, findsOneWidget);
await testData.error();
},
);
testWidgets(
'StreamedStateBuilder error test',
(WidgetTester tester) async {
final testData = EntityStreamedState<String>();
final streamedStateBuilder = EntityStateBuilder<String>(
streamedState: testData,
child: (context, data) {
return Text('test');
},
errorChild: Text('error_text'),
);
unawaited(testData.error(Exception()));
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: streamedStateBuilder,
),
),
);
final errorFinder = find.text('error_text');
expect(errorFinder, findsOneWidget);
},
);
testWidgets(
'StreamedStateBuilder loading test',
(WidgetTester tester) async {
final testData = EntityStreamedState<String>();
final streamedStateBuilder = EntityStateBuilder<String>(
streamedState: testData,
child: (context, data) {
return Text('test');
},
loadingChild: Text('loading_child'),
);
unawaited(testData.loading());
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: streamedStateBuilder,
),
),
);
final loadingFinder = find.text('loading_child');
expect(loadingFinder, findsOneWidget);
},
);
TextFieldStateBuilder
Wrapper over TextFieldStreamedState.
StateBuilder callback is triggered every time new data appears in the stream.
testWidgets(
'TextfieldStreamBuilder content test',
(WidgetTester tester) async {
final testData = TextFieldStreamedState('test');
final textFieldStateBuilder = TextFieldStateBuilder(
state: testData,
stateBuilder: (context, data) {
return Text('test');
});
await tester.pumpWidget(
MaterialApp(
title: 'Flutter Demo',
home: Scaffold(
body: textFieldStateBuilder,
),
),
);
final textFinder = find.text('test');
expect(textFinder, findsOneWidget);
},
);
State
StreamedState
A state of some type wrapped in a stream dictates the widget's state
yourStreamedState.accept(someData);
...
StreamedStateBuilder<T>(
streamedState: yourStreamedState,
builder: (ctx, T data) => Text(data.toString()),
);
EntityStreamedState
A state that have download/error/content status
dataState.loading();
try {
var content = await someRepository.getData();
dataState.content(content);
} catch (e) {
dataState.error(e);
}
...
EntityStateBuilder<Data>(
streamedState: dataState,
child: (data) => DataWidget(data),
loadingChild: LoadingWidget(),
errorChild: ErrorPlaceholder(),
);
Installation
Add relation
to your pubspec.yaml
file:
dependencies:
relation: ^3.0.0
You can use both stable
and dev
versions of the package listed above in the badges bar.
Changelog
All notable changes to this project will be documented in this file.
Issues
For issues, file directly in the main SurfGear repo.
Contribute
If you would like to contribute to the package (e.g. by improving the documentation, solving a bug or adding a cool new feature), please review our contribution guide first and send us your pull request.
Your PRs are always welcome.
How to reach us
Please feel free to ask any questions about this package. Join our community chat on Telegram. We speak English and Russian.
License
Libraries
- relation
- builders