Easy to use State manager for flutter based on observer:eyes: design pattern.
Telescope is more than a normal observer.
Telescope:telescope:
0. Supports all platforms.
- Easy to learn:book:
- Feature rich:hearts:
- Can directly bind to Flutters StateFullWidget and rebuild:recycle: widget on value change.
- Save states on disk and load when needed.
- Telescopes can watch each other with dependsOn() constructor.
- Depends on can be async.
- Caching ability with expireTime option.
- debounceTime option (something like rx-js debounceTime).
- Request a feature here.
- Make it harder to make bugs:beetle::no_entry:.
- With separation of concerns:raised_hands:.
- No setState() needed:no_good:.
- Fast:zap: (just rebuild widgets that need to rebuild).
- Lightweight:hatched_chick: (less then 900KB)
- Flexible:ocean:
- It lets you do it in your way as a library (not a framework):muscle:.
- Can be used beside other state managers:couple:.
flutter pub add telescope
import 'package:telescope/telescope.dart';
In 3 steps.
var textValue = Telescope("default value");
Put this in middle of you widget build function.
@override
Widget build(BuildContext context) {
return Material(
child: SafeArea(
child: Container(
child: Column(children: [
// watch like this ('this' is State that will automatically rebuild on data change)
Text(textValue.watch(this)),
Text(textValue.watch(this)),
Text(textValue.watch(this).length.toString()),
],),
)
)
);
}
Note: You can watch one telescope instance from multiple widgets(example).
You can update telescope.value from anywhere in your code:
onTap: (){
textValue.value += "a";
}
And the widget will get update automatically without calling setState.
You can also subscribe to observable by passing callback like a normal observable.
textValue.subscribe((newValue){
// execute on value change
});
Just implement hashCode getter:
class Human{
int height;
int weight;
Human(this.height,this.weight);
@override
int get hashCode => height*weight;
}
And you are good to go:
var human = Telescope<Human>(null);
Telescopes can be depended on other telescopes.
var height = Telescope(186);
var weight = Telescope(72);
var bmi = Telescope.dependsOn([height,weight], () {
return weight.value / ((height.value/100) * (height.value/100));
});
var showingText = Telescope.dependsOn([bmi], () {
return "weight is ${weight.value} and height is ${height.value} so bmi will be ${bmi.value.toString().substring(0,5)}";
});
So when ever height or weight value get changes, the bmi will calculate itself because it depends on height and weight.
And showingText will calculate itself too, because it depends on bmi.
var bmi = Telescope.dependsOnAsync(0, [height, weight], () async {
return await calculateBMI(height.value, weight.value);
});
var bmi = Telescope.dependsOnAsync(0, [height, weight], () async {
return await calculateBMI(height.value, weight.value);
}, enableCaching: true);
You can also set expire time by passing cacheExpireTime.
debounceTime: will call your async function only if a given time has passed without any changes on dependencies.
var bmi = Telescope.dependsOnAsync(0, [height, weight], () async {
return await calculateBMI(height.value, weight.value);
}, debounceTime: Duration(milliseconds: 500));
It's useful when you want to run your async function when user stop typing or moving slider or...
This will make isCalculatingBMI true on loading and false when loaded, you may need this to show loading animation.
var isCalculatingBMI = Telescope<bool>(false);
var bmi = Telescope.dependsOnAsync(0, [height, weight], () async {
return await calculateBMI(height.value, weight.value);
}, isCalculating: isCalculatingBMI);
You can save telescope data on disk easily like this:
var height = Telescope.saveOnDiskForBuiltInType(187, "bmi_height_input");
So if user close the app and open it again it will load last value of telescope for You.
Telescope implementation for list
- can be dependent
- can save on disk
var items = TelescopeList(["ab", "abb", "bc", "bcc" , "c"]);
You need to implement OnDiskSaveAbility for your object:
For example you have Human class:
class Human{
int height;
int weight;
Human(this.height,this.weight);
@override
int get hashCode => height*weight;
}
Then you need to make other class like this for Human:
class HumanOnDiskAbility implements OnDiskSaveAbility<Human>{
@override
Human parseOnDiskString(String data) {
var sp = data.split(":");
return Human(int.parse(sp[0]), int.parse(sp[1]));
}
@override
String toOnDiskString(Human instance) => "${instance.height}:${instance.weight}";
}
And pass instance of HumanOnDiskAbility to Telescope:
var human = Telescope.saveOnDiskForNonBuiltInType(
Human(187, 72),
"human_for_bmi",
HumanOnDiskAbility()
);
Telescope will use 'parseOnDiskString' and 'toOnDiskString' to serialize and deserialize your object.
This method also can use in TelescopeList in same way.
- Plz:pray: star:star: repo.
- Full documentation.
- Examples.
- Static instance of Telescopes?
- it's not recommend because it decreases re-usability of your code, but in some use-cases it's OK to do that.
- Extends from Telescope?
- Why not? TelescopeList actually extends from Telescope
- Under MIT license