Orientação gerada a partir de informações públicas. Apenas para referência.
Frideos é um pacote abrangente do Flutter que oferece soluções integradas para gerenciamento de estado, programação reativa, animações, efeitos visuais e widgets com temporização. Simplifica o desenvolvimento ao combinar múltiplas utilidades em um único framework coeso. Projetado para aumentar a produtividade, permite que os desenvolvedores criem interfaces dinâmicas e responsivas com pouca quantidade de código repetitivo. O pacote suporta objetos reativos que atualizam automaticamente a interface quando os dados mudam, simplificando o gerenciamento de estado em toda a aplicação. Com controladores de animação e utilitários de tempo embutidos, o Frideos ajuda a criar experiências de usuário suaves e envolventes. Sua arquitetura modular permite o uso seletivo de funcionalidades sem adicionar sobrecarga desnecessária.
Casos de uso
painéis de dados em tempo real
Componentes de interface interativa
Fluxos de onboarding animados
Manipulação de formulários reativos
Exibição de conteúdo com tempo determinado
Principais recursos
Gerenciamento de estado unificado
Objetos reativos com atualização automática
Animações e efeitos embutidos
Agendamento de widget baseado em tempo
Boilerplate mínimo
Arquitetura modular
Indicado para
Desenvolvedores experientes em Flutter
Aplicativos que exigem atualizações em tempo real
aplicações com foco em UI
Equipes que buscam fluxos de trabalho simplificados
Projetos com lógica de estado complexa
Considerações
Pode introduzir uma curva de aprendizado para iniciantes
Personalização limitada por plataforma
Não ideal para aplicativos muito simples
Depende de padrões reativos consistentes
Requer conhecimento dos conceitos de programação reativa
README original
Snapshot do README original do repositório-fonte vinculado. Consulte o repositório para o conteúdo mais recente.
Frideos
An all-in-one package for state management, streams and BLoC pattern, animations and timed widgets, effects.
Quiz game: 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
The core of the package consists of classes that implement the StramedObject interface:
////// Interface for all the StreamedObjects///abstractclassStreamedObject<T> {
/// Getter for the stream exposed by the classes that implement/// the StreamedObject interface.Stream<T> get outStream;
/// Getter for the last value emitted by the stream
T get value;
}
HistoryObject
MemoryValue
StreamedList
StreamedMap
StreamedTransformed
StreamedValue
These 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:
counter += 1;
stream.sink.add(counter);
It becomes just:
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
// In the BLoCfinal count = StreamedValue<int>(initialData: 0);
incrementCounter() {
count.value += 2.0;
}
// ViewValueBuilder<int>(
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<int>( // 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.
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
ValueBuilder<String>(
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
StreamedWidget<String>(
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.):
StreamedWidget<String>(
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.
final streamedList = StreamedList<String>();
// Add to the streamed list the string from the textfieldaddText() {
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.
final streamedMap = StreamedMap<int, String>();
// Add to the streamed map the key/value pair put by the useraddText() {
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
final countMemory = MemoryValue<int>();
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.
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:
// In the BLoC classfinal streamedKey = StreamedTransformed<String, int>();
// In the constructor of the BLoC class
streamedKey.setTransformer(validateKey);
// Validation (e.g. in the BLoC or in a mixin class)final validateKey =
StreamTransformer<String, int>.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<int>(
stream: bloc.streamedKey.outTransformed,
builder: (context, snapshot) {
returnColumn(
children: <Widget>[
Padding(
padding: constEdgeInsets.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
FuturedWidget<String>(
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
ReceiverWidget(stream: streamedValue.outStream),
StreamedSender
Used to make a one-way tunnel beetween two blocs (from blocA to a StremedValue on blocB).
Usage
Define an object that implements the StreamedObject interface in the blocB (e.g. a StreamedValue):
final receiverStr = StreamedValue<String>();
Define a StreamedSender in the blocA:
final tunnelSenderStr = StreamedSender<String>();
Set the receiver in the sender on the class the holds the instances of the blocs:
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.
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).
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.
N.B. The onShow callback is used to trigger an action when the stage shows
Usage
From the StagedObject example:
Declare a map <int, Stage>
Here the map is in the view and is set in the BLoC class by the setStagesMap.
Map<int, Stage> get stagesMap => <int, Stage>{
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: () {}),
}
In the BLoC
final text = StreamedValue<String>();
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<int, Stage> stagesMap) {
staged.setStagesMap(stagesMap);
}
// This method is then called from a button in the viewstart() {
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 stagesendNextStageText() {
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();
}
}
In the view:
// Setting the map in the build methodStagedObjectBloc 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
Usage
Declare a map <int, Stage>
Here the map is in the view and is set in the BLoC class by the setStagesMap.
Map<int, Stage> get stagesMap => <int, Stage>{
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: () {}),
}
In the view:
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);
}),