Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/frideosapps/frideos_flutter
An all-in-one Fllutter package for state management, reactive objects, animations, effects, timed widgets etc.
https://github.com/frideosapps/frideos_flutter
bloc bloc-pattern dart dart-library dart2 flutter flutter-apps flutter-examples flutter-library flutter-package flutter-widget frideos library reactive-programming rxdart sharedpreferences sharedpreferences-helper state-management streams widgets-timing
Last synced: 3 days ago
JSON representation
An all-in-one Fllutter package for state management, reactive objects, animations, effects, timed widgets etc.
- Host: GitHub
- URL: https://github.com/frideosapps/frideos_flutter
- Owner: frideosapps
- License: bsd-2-clause
- Created: 2019-01-19T13:53:19.000Z (almost 6 years ago)
- Default Branch: master
- Last Pushed: 2023-11-22T09:51:32.000Z (12 months ago)
- Last Synced: 2024-06-29T19:32:51.927Z (5 months ago)
- Topics: bloc, bloc-pattern, dart, dart-library, dart2, flutter, flutter-apps, flutter-examples, flutter-library, flutter-package, flutter-widget, frideos, library, reactive-programming, rxdart, sharedpreferences, sharedpreferences-helper, state-management, streams, widgets-timing
- Language: Dart
- Homepage: https://pub.dev/packages/frideos
- Size: 964 KB
- Stars: 189
- Watchers: 13
- Forks: 22
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Frideos [![pub package](https://img.shields.io/pub/v/frideos.svg)](https://pub.dartlang.org/packages/frideos)
An all-in-one package for state management, streams and BLoC pattern, animations and timed widgets, effects.
## Contents
### [1. State management](#state-management)
**Getting started**
- StreamedValue
- AppStateModel
- AppStateProvider
- ValueBuilder
- StreamedWidget
#### Specialized StreamedObjects
- StreamedList
- StreamedMap
- HistoryObject
- MemoryValue
- StreamedTransformed##### Other
- FuturedWidget
- ReceiverWidget
- StreamedSender, ListSender, and MapSender### [2. Animations and timing](#animations)
- AnimationTween
- AnimationCreate
- AnimationCurved
- CompositeItem
- AnimationComposite
- CompositeCreate
- ScenesObject
- ScenesCreate
- StagedObject
- StagedWidget
- WavesWidget
- ScrollingText### [3. Effects](#effects)
- LinearTransition
- CurvedTransition
- FadeInWidget
- FadeOutWidget
- BlurWidget
- BlurInWidget
- BlurOutWidget
- AnimatedBlurWidget## Articles and examples
- [A book trailer with Flutter web](https://itnext.io/me-flutter-web-and-the-making-of-an-experimental-book-trailer-8f1625173759)
- [Quiz game](https://github.com/frideosapps/trivia_example): a simple trivia game built with Flutter and this package. You can read an article about this example here: https://medium.com/flutter-community/flutter-how-to-build-a-quiz-game-596d0f369575
- [Todo App](https://github.com/brianegan/flutter_architecture_samples/tree/master/frideos_library): an implementation of the Todo App of the [Flutter Architecture Samples](https://github.com/brianegan/flutter_architecture_samples) repository using this package.
- [Frideos examples](https://github.com/frideosapps/frideos_examples): an example app to show how to use some features of this library.
- Streamed objects
- Streamed collections
- TimerObject: a simple stopwatch
- StagedObject
- StagedWidget
- AnimatedObject
- Multiple selection and tunnel pattern (to share data between two blocs)
- LinearTransition
- CurvedTransition
- Blur (fixed, in, out, animated)
- WavesWidget
- Sliders
- Products catalog
- [Dynamic fields validation](https://github.com/frideosapps/dynamic_fields_validation): a Flutter example on how to validate dynamically created fields with the BLoC pattern and this package.- [Theme changer](https://github.com/frideosapps/theme_changer): a simple starter app with a drawer, app state management, dynamic theme changer and persistent theme using the sharedpreferences.
- [Counter](https://github.com/frideosapps/counter): a simple app using the BLoC pattern showing a counter implemented with this library.
- [Blood pressure](https://github.com/frideosapps/bloodpressure): an example of a medical app built with Flutter for the classification of the arterial blood pressure.
- [Pair game](https://github.com/frideosapps/pair_game): a simple pair game (multiple selections, animations, tunnel pattern).
## Dependencies- [RxDart](https://pub.dartlang.org/packages/rxdart)
# State management### Getting started
The core of the package consists of classes that implement the StramedObject interface:
```dart
///
/// Interface for all the StreamedObjects
///
abstract class StreamedObject {
/// Getter for the stream exposed by the classes that implement
/// the StreamedObject interface.
Stream get outStream;/// Getter for the last value emitted by the stream
T get value;
}
```- HistoryObject
- MemoryValue
- StreamedList
- StreamedMap
- StreamedTransformed
- StreamedValueThese objects are then used (e.g. in classes extending the AppStateModel interface) in combination with the **ValueBuilder** widget (or StreamedWidget/StreamBuilder), to make the UI reactive to their changes.
### StreamedValue
The **StreamedValue** is the simplest class that implements this interface.
Every time a new value is set, this is compared to the latest one and if it is different, it is sent to stream. Used in tandem with `ValueBuilder` (or StreamedWidget/StreamBuilder) it automatically triggers the rebuild of the widgets returned by its builder.So for example, instead of:
```dart
counter += 1;
stream.sink.add(counter);
```It becomes just:
```dart
counter.value += 1;
```It can be used even with `StreamedWidget` and `StreamBuilder` by using its stream getter `outStream`.
N.B. when the type is not a basic type (e.g int, double, String etc.) and the value of a property of the object is changed, it is necessary to call the `refresh` method to update the stream.
#### Example
```dart
// In the BLoC
final count = StreamedValue(initialData: 0);incrementCounter() {
count.value += 2.0;
}// View
ValueBuilder(
streamed: bloc.count, // no need of the outStream getter with ValueBuilder
builder: (context, snapshot) =>
Text('Value: ${snapshot.data}'),
noDataChild: Text('NO DATA'),
),
RaisedButton(
color: buttonColor,
child: Text('+'),
onPressed: () {
bloc.incrementCounter();
},
),// As an alternative:
//
// StreamedWidget(
// stream: bloc.count.outStream,
// builder: (context, snapshot) => Text('Value: ${snapshot.data}'),
// noDataChild: Text('NO DATA'),
//),
```If on debugMode, on each update the `timesUpdated` increases showing how many times the value has been updated.
N.B. For collections use `StreamedList` and `StreamedMap` instead.
### AppStateModel and AppStateProvider
These reactive objects can be used in classes extending the AppStateModel interface, and provided to the widgets tree using the AppStateProvider widget.
From the "theme changer" example:
#### 1. Create a model for the app state:
```dart
class AppState extends AppStateModel {
List themes;
StreamedValue currentTheme;AppState() {
print('-------APP STATE INIT--------');themes = List();
themes.addAll([
MyTheme(
name: 'Default',
brightness: Brightness.light,
backgroundColor: Colors.blue[50],
scaffoldBackgroundColor: Colors.blue[50],
primaryColor: Colors.blue,
primaryColorBrightness: Brightness.dark,
accentColor: Colors.blue[300],
),
MyTheme(
name: 'Teal',
brightness: Brightness.light,
backgroundColor: Colors.teal[50],
scaffoldBackgroundColor: Colors.teal[50],
primaryColor: Colors.teal[600],
primaryColorBrightness: Brightness.dark,
accentColor: Colors.teal[300],
),
MyTheme(
name: 'Orange',
brightness: Brightness.light,
backgroundColor: Colors.orange[50],
scaffoldBackgroundColor: Colors.orange[50],
primaryColor: Colors.orange[600],
primaryColorBrightness: Brightness.dark,
accentColor: Colors.orange[300],
),
]);currentTheme = StreamedValue();
}void setTheme(MyTheme theme) => currentTheme.value = theme;
@override
void init() => currentTheme.value = themes[0];
@override
dispose() {
print('---------APP STATE DISPOSE-----------');
currentTheme.dispose();
}
}
```#### 2. Wrap the MaterialApp in the AppStateProvider:
```dart
void main() => runApp(App());class App extends StatefulWidget {
@override
_AppState createState() => _AppState();
}class _AppState extends State {
AppState appState;@override
void initState() {
super.initState();
appState = AppState();
}@override
Widget build(BuildContext context) {
return AppStateProvider(
appState: appState,
child: MaterialPage(),
);
}
}
```#### 3. Consume the data:
```dart
class MaterialPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var theme = AppStateProvider.of(context).currentTheme;return ValueBuilder(
streamed: theme,
builder: (context, snapshot) {
return MaterialApp(
title: "Theme and drawer starter app",
theme: _buildThemeData(snapshot.data),
home: HomePage(),
);
},
);
}_buildThemeData(MyTheme appTheme) {
return ThemeData(
brightness: appTheme.brightness,
backgroundColor: appTheme.backgroundColor,
scaffoldBackgroundColor: appTheme.scaffoldBackgroundColor,
primaryColor: appTheme.primaryColor,
primaryColorBrightness: appTheme.primaryColorBrightness,
accentColor: appTheme.accentColor,
);
}
}
```#### 4. Change the data (using a stream):
```dart
class SettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
var appState = AppStateProvider.of(context);_buildThemesList() {
return appState.themes.map((MyTheme appTheme) {
return DropdownMenuItem(
value: appTheme,
child: Text(appTheme.name, style: TextStyle(fontSize: 14.0)),
);
}).toList();
}return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"Settings",
),
),
body: Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'Choose a theme:',
style: TextStyle(fontWeight: FontWeight.w500),
),
),
ValueBuilder(
streamed: appState.currentTheme,
builder: (context, snapshot) {
return DropdownButton(
hint: Text("Status"),
value: snapshot.data,
items: _buildThemesList(),
onChanged: appState.setTheme,
);
},
),
],
),
],
),
),
);
}
}
```### ValueBuilder
ValueBuilder extends the [StreamBuilder] widget providing some callbacks to handle the state of the stream and returning a [Container] if `noDataChild` is not provided, in order to avoid checking `snapshot.hasData`.
N.B. To use when there is no need to receive a _null value_.
It takes as a `streamed` parameter an object implementing the [StreamedObject] interface and triggers the rebuild of the widget whenever the stream emits a new event.
#### Usage
```dart
ValueBuilder(
streamed: streamedValue,
builder: (context, snasphot) => Text(snasphot.data),
initialData: // Data to provide for the initial snapshot
noDataChild: // Widget to show when the stream has no data
onNoData: () => // or Callback
errorChild: // Widget to show on error
onError: (error) => // or Callback
)
```If no [noDataChild] widget or [onNoData] callback is provided then a [Container] is returned.
If no [errorChild] widget or no [onError] callback is provided then a [Container] is returned.
N.B. The callbacks are executed only if their respective child is not provided.
### StreamedWidget
StreamedWidget extends the [StreamBuilder] widget providing
some callbacks to handle the state of the stream and returning a
[Container] if `noDataChild` is not provided, in order to avoid
checking `snapshot.hasData`.N.B. To use when there is no need to receive a _null value_.
It takes as a `stream` parameter a [Stream] and triggers the rebuild of the widget whenever the stream emits a new event.
If no [noDataChild] widget or [onNoData] callback is provided then a [Container] is returned.
If no [errorChild] widget or no [onError] callback is provided then a [Container] is returned.
#### Usage
```dart
StreamedWidget(
stream: stream,
builder: (context, snasphot) => Text(snasphot.data),
noDataChild: // Widget to show when the stream has no data
onNoData: () => // or Callback
errorChild: // Widget to show on error
onError: (error) => // or Callback
)
```In case of an object implementing the StreamedObject interface (eg. StreamedValue, StreameList etc.):
```dart
StreamedWidget(
stream: streamedObject.outStream, // outStream getter
builder: (context, snasphot) => Text(snasphot.data),
noDataChild: // Widget to show when the stream has no data
onNoData: () => // or Callback
errorChild: // Widget to show on error
onError: (error) => // or Callback
)
```N.B. The callbacks are executed only if their respective child is not provided.
## Specialized StreamedObjects
### StreamedList
This class has been created to work with lists. It works like `StreamedValue`.
To modify the list (e.g. adding items) and update the stream automatically
use these methods:- `AddAll`
- `addElement`
- `clear`
- `removeAt`
- `removeElement`
- `replace`
- `replaceAt`For other direct actions on the list, to update the stream call
the `refresh` method instead.#### Usage
e.g. adding an item:
```dart
streamedList.addElement(item);
```it is the same as:
```dart
streamedList.value.add(item);
streamedList.refresh();
```From the StreamedList example:
```dart
final streamedList = StreamedList();// Add to the streamed list the string from the textfield
addText() {
streamedList.addElement(streamedText.value);// Or, as an alternative:
// streamedList.value.add(streamedText.value);
// streamedList.refresh(); // To refresh the stream with the new value
}
```### StreamedMap
This class has been created to work with maps, it works like `StreamedList`.
To modify the list (e.g. adding items) and update the stream automatically
use these methods:- `addKey`
- `removeKey`
- `clear`For other direct actions on the map, to update the stream call
the `refresh` method instead.#### Usage
e.g. adding a key/value pair:
```dart
streamedMap.addKey(1, 'first');
```it is the same as:
```dart
streamedMap.value[1] = 'first';
streamedList.refresh();
```From the streamed map example:
```dart
final streamedMap = StreamedMap();// Add to the streamed map the key/value pair put by the user
addText() {
var key = int.parse(streamedKey.value);
var value = streamedText.value;streamedMap.addKey(key, value);
// Or, as an alternative:
//streamedMap.value[key] = value;
//streamedMap.refresh();
}
```### MemoryValue
The `MemoryValue` has a property to preserve the previous value. The setter checks for the new value, if it is different from the one already stored, this one is given `oldValue` before storing and streaming the new one.
#### Usage
```dart
final countMemory = MemoryValue();countMemory.value // current value
couneMemory.oldValue // previous value
```### HistoryObject
Extends the `MemoryValue` class, adding a `StreamedList`. Useful when it is need to store a value in a list.
```dart
final countHistory = HistoryObject();incrementCounterHistory() {
countHistory.value++;
}saveToHistory() {
countHistory.saveValue();
}
```### StreamedTransformed
A particular class the implement the `StreamedObject` interface, to use when there is the need of a `StreamTransformer` (e.g. stream transformation, validation of input
fields, etc.).#### Usage
From the StreamedMap example:
```dart
// In the BLoC class
final streamedKey = StreamedTransformed();// In the constructor of the BLoC class
streamedKey.setTransformer(validateKey);// Validation (e.g. in the BLoC or in a mixin class)
final validateKey =
StreamTransformer.fromHandlers(handleData: (key, sink) {
var k = int.tryParse(key);
if (k != null) {
sink.add(k);
} else {
sink.addError('The key must be an integer.');
}
});// In the view:
StreamBuilder(
stream: bloc.streamedKey.outTransformed,
builder: (context, snapshot) {
return Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 12.0,
horizontal: 20.0,
),
child: TextField(
style: TextStyle(
fontSize: 18.0,
color: Colors.black,
),
decoration: InputDecoration(
labelText: 'Key:',
hintText: 'Insert an integer...',
errorText: snapshot.error,
),
// To avoid the user could insert text use the TextInputType.number
// Here is commented to show the error msg.
//keyboardType: TextInputType.number,
onChanged: bloc.streamedKey.inStream,
),
),
],
);
}),
```## Other
### FuturedWidget
FuturedWidget is a wrapper for the [FutureBuilder] widget. It provides some callbacks to handle the state of the future and returning a [Container] if `onWaitingChild` is not provided, in order to avoid checking `snapshot.hasData`.
#### Usage
```dart
FuturedWidget(
future: future,
builder: (context, snasphot) => Text(snasphot.data),
initialData: // Data to provide if the snapshot is null or still not completed
waitingChild: // Widget to show on waiting
onWaiting: () => // or Callback
errorChild: // Widget to show on error
onError: (error) => // or Callback
)
```If no [onWaitingChild] widget or [onWaiting] callback is provided then a [Container] is returned.
If no [errorChild] widget or no [onError] callback is provided then a [Container] is returned.
N.B. The callbacks are executed only if their respective child is not provided.
### ReceiverWidget
Used with a StreamedValue when the type is a widget to directly stream a widget to the view. Under the hood a StreamedWidget handles the stream and shows the widget.
#### Usage
```dart
ReceiverWidget(stream: streamedValue.outStream),
```### StreamedSender
Used to make a one-way tunnel beetween two blocs (from blocA to a StremedValue on blocB).
#### Usage
1. #### Define an object that implements the `StreamedObject` interface in the blocB (e.g. a `StreamedValue`):
```dart
final receiverStr = StreamedValue();
```2. #### Define a `StreamedSender` in the blocA:
```dart
final tunnelSenderStr = StreamedSender();
```3. #### Set the receiver in the sender on the class the holds the instances of the blocs:
```dart
blocA.tunnelSenderStr.setReceiver(blocB.receiverStr);
```4. #### To send data from blocA to blocB then:
```dart
tunnelSenderStr.send("Text from blocA to blocB");
```### ListSender and MapSender
Like the StreamedSender, but used with collections.
#### Usage
1. #### Define a `StreamedList` or `StreamedMap` object in the blocB
```dart
final receiverList = StreamedList();
final receiverMap = StreamedMap();
```2. #### Define a `ListSender`/`MapSender` in the blocA
```dart
final tunnelList = ListSender();
final tunnelMap = MapSender();
```3. #### Set the receiver in the sender on the class the holds the instances of the blocs
```dart
blocA.tunnelList.setReceiver(blocB.receiverList);
blocA.tunnelMap.setReceiver(blocB.receiverMap);
```4. #### To send data from blocA to blocB then:
```dart
tunnelList.send(list);
tunnelMap.send(map);
```# Animations
### AnimationTween
```dart
anim = AnimationTween(
duration: Duration(milliseconds: 120000),
setState: setState,
tickerProvider: this,
begin: 360.0,
end: 1.0,
onAnimating: _onAnimating,
);opacityAnim = AnimationTween(
begin: 0.5,
end: 1.0,
controller: anim.baseController,
);growAnim = AnimationTween(
begin: 1.0,
end: 30.0,
controller: anim.baseController,
);// Play animation
anim.forward();// Called on each frame
void _onAnimating(AnimationStatus status) {
if (status == AnimationStatus.completed) {
anim.reverse();
}
if (status == AnimationStatus.dismissed) {
anim.forward();
}
}// Example
Opacity(
opacity: opacityAnim.value,
child: Container(
alignment: Alignment.center,
height: 100 + growAnim.value,
width: 100 + growAnim.value,
decoration: BoxDecoration(
color: Colors.blue,
boxShadow: [
BoxShadow(blurRadius: anim.value),
],
),
),
```### AnimationCreate
```dart
AnimationCreate(
begin: 0.1,
end: 1.0,
curve: Curves.easeIn,
duration: 1000,
repeat: true,
reverse: true,
builder: (context, anim) {
return Opacity(
opacity: anim.value,
child: Text(
'Loading...',
style: TextStyle(
color: Colors.white,
fontSize: 26.0,
),
),
);
```### AnimationCurved
```dart
circleAnim = AnimationCurved(
duration: Duration(milliseconds: 7000),
setState: setState,
tickerProvider: this,
begin: 360.0,
end: 1.0,
curve: Curves.bounceInOut,
onAnimating: _onAnimating,
);circleAnim.forward();
```### CompositeItem and AnimationComposite
```dart
compAnim = AnimationComposite(
duration: Duration(milliseconds: 1750),
setState: setState,
tickerProvider: this,
composite: {
'background': CompositeItem(
begin: Colors.amber, end: Colors.blue, curve: Curves.elasticIn),
'grow': CompositeItem(begin: 1.0, end: 40.0),
'rotate': CompositeItem(
begin: math.pi / 4, end: math.pi, curve: Curves.easeIn),
'color': CompositeItem(
begin: Colors.green, end: Colors.orange, curve: Curves.elasticIn),
'shadow': CompositeItem(begin: 5.0, end: 30.0),
'rounded': CompositeItem(
begin: 0.0,
end: 150.0,
curve: Curves.easeIn,
)
});movAnim = AnimationComposite(
duration: Duration(milliseconds: 1750),
setState: setState,
tickerProvider: this,
composite: {
'upper': CompositeItem(
begin: Offset(-60.0, -30.0),
end: Offset(80.0, 15.0),
curve: Curves.easeIn),
'lower': CompositeItem(
begin: Offset(-80.0, 0.0),
end: Offset(70.0, -25.0),
curve: Curves.easeInCirc),
});// Example
Transform.translate(
offset: movAnim.value('lower'),
child: Transform.rotate(
angle: compAnim.value('rotate'),
child: Container(
alignment: Alignment.center,
height: 100 + compAnim.value('grow'),
width: 100 + compAnim.value('grow'),
decoration: BoxDecoration(
color: compAnim.value('color'),
boxShadow: [
BoxShadow(blurRadius: compAnim.value('shadow')),
],
borderRadius: BorderRadius.circular(
compAnim.value('rounded'),
),
),
),
),
),
```### CompositeCreate
```dart
enum AnimationType {
fadeIn,
scale,
fadeOut,
}@override
Widget build(BuildContext context) {
return CompositeCreate(
duration: duration,
repeat: false,
compositeMap: {
AnimationType.fadeIn: CompositeItem(
begin: 0.2,
end: 1.0,
curve: const Interval(
0.0,
0.2,
curve: Curves.linear,
),
),
AnimationType.scale: CompositeItem(
begin: reverse ? 0.8 : 1.0,
end: reverse ? 1.0 : 0.8,
curve: const Interval(
0.2,
0.6,
curve: Curves.linear,
),
),
AnimationType.fadeOut: CompositeItem(
begin: 1.0,
end: 0.0,
curve: Interval(
0.7,
0.8,
curve: Curves.linear,
),
),
},
onCompleted: onCompleted,
builder: (context, comp) {
return Transform.scale(
scale: comp.value(AnimationType.scale),
child: Opacity(
opacity: comp.value(AnimationType.fadeIn),
child: Opacity(
opacity: comp.value(AnimationType.fadeOut),
child: Text(
'Text',
```### ScenesObject
A complex class to hadle the rendering of scenes over the time.
It takes a collection of "Scenes" and triggers the visualization of
the widgets at a given time (relative o absolute timing).
For example to make a demostration on how to use an application,
showing the widgets and pages along with explanations.Every scene is handled by using the Scene class:
```dart
class Scene {
Widget widget;
int time; // milliseconds
Function onShow = () {};
Scene({this.widget, this.time, this.onShow});
}
```##### N.B. The onShow callback is used to trigger an action when the scene shows
#### Usage
From the ScenesObject example:#### 1 - Declare a list of scenes
```dart
final ScenesObject scenesObject = ScenesObject();
```
#### 2 - Add some scenes
```dart
scenes.addAll([
Scene(
time: 4000,
widget: SingleScene(text: 'Scene 1', color: Colors.blueGrey),
onShow: () => print('Showing scene 1'),
),
Scene(
time: 4000,
widget: SingleScene(text: 'Scene 2', color: Colors.orange),
onShow: () => print('Showing scene 1'),
)
]);
// The singleScene widget:
class SingleScene extends StatelessWidget {
const SingleScene({Key key, this.text, this.color}) : super(key: key);
final String text;
final Color color;
@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
color: color,
child: Text(text),
);
}
}
```
#### 3 - Setup the ScenesObject and play the scenes```dart
scenesObject
..setScenesList(scenes)
..setCallback(() => print('Called on start'))
..setOnEndCallback(scenesObject.startScenes); // Replay the scenes at the end
// For e.g. on tap on a button:
scenesObject.startScenes();
```### ScenesCreate
This widget uses a [ScenesObject] for the timing of the widgets
visualization.It takes as a parameter a List and plays every [Scene].
By default to change the stage is used the relative time, so the time
parameter of the [Scene] indicates how much time the stage will lasts.
Instead, to specify the absolute time, set to true the [absoluteTiming]
flag, in this case the time parameter indicates the absolute time when
to show the scene.The [onStart] is used to call a function when the ScenesObject begins
to play the stages.The [onEnd] callback is called at the end of the last stage when the timeing
is relative (the [absoluteTiming] flag is set to false).#### Usage
From the ScenesObject example:
```dart
ScenesCreate(
scenes: [
Scene(
widget: SingleScene(
color: Colors.white,
text: 'Scene 1',
),
time: 3500,
onShow: () {
print('Showing scene 1');
}),
Scene(
widget: SingleScene(
color: Colors.blue,
text: 'Scene 2',
),
time: 3500,
onShow: () {
print('Showing scene 2');
}),
Scene(
widget: SingleScene(
color: Colors.brown,
text: 'Scene 3',
),
time: 3500,
onShow: () {
print('Showing scene 3');
}),
],
onStart: () => print('Start playing scenes!'),
onEnd: () => print('End playing scenes!'),
),// The singleScene widget:
class SingleScene extends StatelessWidget {
const SingleScene({Key key, this.text, this.color}) : super(key: key);final String text;
final Color color;@override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
color: color,
child: Text(text),
);
}
}
```### StagedObject
A complex class to hadle the rendering of widgets over the time. It takes a collection of "Stages" and triggers the visualization of the widgets at a given time (relative o absolute timing). For example to make a demostration on how to use an application, showing the widgets and pages along with explanations.
![StagedObject](https://i.imgur.com/9XLb7JD.gif)
Every stage is handled by using the Stage class:
```dart
class Stage {
Widget widget;
int time; // milliseconds
Function onShow = () {};
Stage({this.widget, this.time, this.onShow});
}
```##### N.B. The onShow callback is used to trigger an action when the stage shows
#### Usage
From the StagedObject example:
1. #### Declare a map
Here the map is in the view and is set in the BLoC class by the setStagesMap.```dart
Map get stagesMap => {
0: Stage(
widget: Container(
width: 200.0,
height: 200.0,
color: Colors.indigo[200],
alignment: Alignment.center,
key: Key('0'),
child: ScrollingText(
text:
'This stage will last 8 seconds. By the onShow call back it is possibile to assign an action when the widget shows.',
scrollingDuration: 2000,
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
fontWeight: FontWeight.w500)),
),
time: 8000,
onShow: () {}),
1: Stage(
widget: Container(
width: 200.0,
height: 200.0,
color: Colors.indigo[200],
alignment: Alignment.center,
key: Key('00'),
child: ScrollingText(
text: 'The next widgets will cross fade.',
scrollingDuration: 2000,
),
),
time: 8000,
onShow: () {}),}
```2. #### In the BLoC
```dart
final text = StreamedValue();
final staged = StagedObject();// The map can be set through the constructor of the StagedObject
// or by the setStagesMap method like in this case.
setMap(Map stagesMap) {
staged.setStagesMap(stagesMap);
}// This method is then called from a button in the view
start() {
if (staged.getMapLength() > 0) {
staged.setCallback(sendNextStageText);
staged.startStages();
}
}// By this method we get the next stage to show it
// in a little box below the current stage
sendNextStageText() {
var nextStage = staged.getNextStage();
if (nextStage != null) {
text.value = "Next stage:";
widget.value = nextStage.widget;
stage.value = StageBridge(
staged.getStageIndex(), staged.getCurrentStage(), nextStage);
} else {
text.value = "This is the last stage";
widget.value = Container();
}
}```
3. #### In the view:
```dart
// Setting the map in the build method
StagedObjectBloc bloc = BlocProvider.of(context);
bloc.setMap(stagesMap);// To show the current widget on the view using the ReceiverWidget.
// As an alternative it can be used the StreamedWidget/StreamBuilder.
ReceiverWidget(
stream: bloc.staged.widgetStream,
),
```### StagedWidget
![StagedWidget](https://i.imgur.com/nCsbJCy.gif)
#### Usage
1. #### Declare a map
Here the map is in the view and is set in the BLoC class by the setStagesMap.```dart
Map get stagesMap => {
0: Stage(
widget: Container(
width: 200.0,
height: 200.0,
color: Colors.indigo[200],
alignment: Alignment.center,
key: Key('0'),
child: ScrollingText(
text:
'This stage will last 8 seconds. By the onShow call back it is possibile to assign an action when the widget shows.',
scrollingDuration: 2000,
style: TextStyle(
color: Colors.blue,
fontSize: 18.0,
fontWeight: FontWeight.w500)),
),
time: 8000,
onShow: () {}),
1: Stage(
widget: Container(
width: 200.0,
height: 200.0,
color: Colors.indigo[200],
alignment: Alignment.center,
key: Key('00'),
child: ScrollingText(
text: 'The next widgets will cross fade.',
scrollingDuration: 2000,
),
),
time: 8000,
onShow: () {}),}
```2. #### In the view:
```dart
StagedWidget(
stagesMap: stagesMap,
onStart: // function to call,
onEnd: () {
// Function to call at the end of the last stage
// (only if relative timing):
// e.g. Navigator.pop(context);
}),
```### WavesWidget
#### Usage
```dart
WavesWidget(
width: 128.0,
height: 128.0,
color: Colors.red,
child: Container(
color: Colors.red[400],
),
```### ScrollingText
#### Usage
```dart
ScrollingText(
text: 'Text scrolling (during 8 seconds).',
scrollingDuration: 2000, // in milliseconds
style: TextStyle(color: Colors.blue,
fontSize: 18.0, fontWeight: FontWeight.w500),
),
```# Effects
### LinearTransition
Linear cross fading transition between two widgets, it can be used with the `StagedObject`.
![LinearTransition](https://i.imgur.com/viGPpCu.gif)
#### Usage
```dart
LinearTransition(
firstWidget: Container(height: 100.0, width: 100.0,
color: Colors.blue),
secondWidget: Container(height: 100.0, width: 100.0,
color: Colors.lime),
transitionDuration: 4000,
),
```### CurvedTransition
Cross fading transition between two widgets. This uses the Flutter way to make an animation.
![CurvedTransition](https://i.imgur.com/kxWOKMU.gif)
#### Usage
```dart
CurvedTransition(
firstWidget: Container(height: 100.0, width: 100.0,
color: Colors.blue),
secondWidget: Container(height: 100.0, width: 100.0,
color: Colors.lime),
transitionDuration: 4000,
curve: Curves.bounceInOut,
),
```### FadeInWidget
#### Usage
```dart
FadeInWidget(
duration: 7000,
child: ScrollingText(
text: 'Fade in text',
scrollingDuration: 2000,
style: TextStyle(
color: Colors.blue,
fontSize: 94.0,
fontWeight: FontWeight.w500,
),
),
),
```### FadeOutWidget
#### Usage
```dart
FadeOutWidget(
duration: 7000,
child: ScrollingText(
text: 'Fade out text',
scrollingDuration: 2000,
style: TextStyle(
color: Colors.blue,
fontSize: 94.0,
fontWeight: FontWeight.w500,
),
),
),
```### BlurWidget
![Blur](https://i.imgur.com/Q8CJboZ.png)
#### Usage
```dart
BlurWidget(
sigmaX: 2.0,
sigmaY: 3.0,
child: Text('Fixed blur')
)
```### BlurInWidget
#### Usage
```dart
BlurInWidget(
initialSigmaX: 2.0,
initialSigmaY: 12.0,
duration: 5000,
refreshTime: 20,
child: Text('Blur out'),
)
```### BlurOutWidget
#### Usage
```dart
BlurOutWidget(
finalSigmaX: 2.0,
finalSigmaY: 12.0,
duration: 5000,
refreshTime: 20,
child: Text('Blur out'),
)
```### AnimatedBlurWidget
#### Usage
```dart
AnimatedBlurWidget(
initialSigmaX: 2.0,
initialSigmaY: 3.0,
finalSigmaX: 2.0,
finalSigmaY: 3.0,
duration: 5000,
reverseAnimation: true,
loop: true,
refreshTime: 20,
child: Text('Fixed blur')
)
```