Skip to content

Latest commit

 

History

History
238 lines (198 loc) · 6.79 KB

README.md

File metadata and controls

238 lines (198 loc) · 6.79 KB

Telescope


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.

  1. Easy to learn:book:
    1. You can learn it in 5-10 min by reading README.
    2. Also see examples.
    3. Full dart standard documentation here.
  2. Feature rich:hearts:
    1. Can directly bind to Flutters StateFullWidget and rebuild:recycle: widget on value change.
    2. Save states on disk and load when needed.
    3. Telescopes can watch each other with dependsOn() constructor.
    4. Depends on can be async.
    5. Caching ability with expireTime option.
    6. debounceTime option (something like rx-js debounceTime).
    7. Request a feature here.
  3. Make it harder to make bugs:beetle::no_entry:.
    1. With separation of concerns:raised_hands:.
    2. No setState() needed:no_good:.
  4. Fast:zap: (just rebuild widgets that need to rebuild).
  5. Lightweight:hatched_chick: (less then 900KB)
  6. Flexible:ocean:
    1. It lets you do it in your way as a library (not a framework):muscle:.
    2. Can be used beside other state managers:couple:.

Installation:

flutter pub add telescope

Import:

import 'package:telescope/telescope.dart';

How to use

In 3 steps.

1. Make a telescope instance:

var textValue = Telescope("default value");

2. Watch(this):

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).

3. Update value:

You can update telescope.value from anywhere in your code:

onTap: (){
  textValue.value += "a";
}

Boom:

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
});

Non Builtin Types

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);

Other features:

Depends on:

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.


Async way:

var bmi = Telescope.dependsOnAsync(0, [height, weight], () async {
  return await calculateBMI(height.value, weight.value);
});

Caching:

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.


Debounce:

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...


Observable on loading state:

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);

Save On Disk

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.

TelescopeList

Telescope implementation for list

  • can be dependent
  • can save on disk
var items = TelescopeList(["ab", "abb", "bc", "bcc" , "c"]);

Save non built in values on disk

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.

Last Words:

  • 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