roi peker

README docs additions!

- fixes #470
- added main README section docs called "Useful tips" where i mentioned some stuffs..
Showing 1 changed file with 259 additions and 33 deletions
@@ -355,23 +355,25 @@ return GetMaterialApp( @@ -355,23 +355,25 @@ return GetMaterialApp(
355 355
356 ## Change Theme 356 ## Change Theme
357 357
358 -Please do not use any higher level widget than GetMaterialApp in order to update it. This can trigger duplicate keys. A lot of people are used to the prehistoric approach of creating a "ThemeProvider" widget just to change the theme of your app, and this is definitely NOT necessary with Get. 358 +Please do not use any higher level widget than `GetMaterialApp` in order to update it. This can trigger duplicate keys. A lot of people are used to the prehistoric approach of creating a "ThemeProvider" widget just to change the theme of your app, and this is definitely NOT necessary with **GetX™**.
359 359
360 -You can create your custom theme and simply add it within Get.changeTheme without any boilerplate for that: 360 +You can create your custom theme and simply add it within `Get.changeTheme` without any boilerplate for that:
361 361
362 ```dart 362 ```dart
363 Get.changeTheme(ThemeData.light()); 363 Get.changeTheme(ThemeData.light());
364 ``` 364 ```
365 365
366 -If you want to create something like a button that changes the theme with onTap, you can combine two Get APIs for that, the api that checks if the dark theme is being used, and the theme change API, you can just put this within an onPressed: 366 +If you want to create something like a button that changes the Theme in `onTap`, you can combine two **GetX™** APIs for that:
  367 +- The api that checks if the dark `Theme` is being used.
  368 +- And the `Theme` Change API, you can just put this within an `onPressed`:
367 369
368 ```dart 370 ```dart
369 Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark()); 371 Get.changeTheme(Get.isDarkMode? ThemeData.light(): ThemeData.dark());
370 ``` 372 ```
371 373
372 -When darkmode is activated, it will switch to the light theme, and when the light theme is activated, it will change to dark. 374 +When `.darkmode` is activated, it will switch to the _light theme_, and when the _light theme_ becomes active, it will change to _dark theme_.
373 375
374 -If you want to know in depth how to change the theme, you can follow this tutorial on Medium that even teaches the persistence of the theme using Get: 376 +If you want to know in depth how to change the Theme, you can follow this tutorial on Medium which even teaches the persistence of the theme using **GetX™**:
375 377
376 - [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr). 378 - [Dynamic Themes in 3 lines using Get](https://medium.com/swlh/flutter-dynamic-themes-in-3-lines-c3b375f292e3) - Tutorial by [Rod Brown](https://github.com/RodBr).
377 379
@@ -417,60 +419,73 @@ Get.offNamedUntil() @@ -417,60 +419,73 @@ Get.offNamedUntil()
417 //Check in what platform the app is running 419 //Check in what platform the app is running
418 GetPlatform.isAndroid 420 GetPlatform.isAndroid
419 GetPlatform.isIOS 421 GetPlatform.isIOS
  422 +GetPlatform.isMacOS
  423 +GetPlatform.isWindows
  424 +GetPlatform.isLinux
  425 +GetPlatform.isFuchsia
  426 +
  427 +//Check the device type
  428 +GetPlatform.isMobile
  429 +GetPlatform.isDesktop
  430 +//All platforms are supported independently in web!
  431 +//You can tell if you are running inside a browser
  432 +//on Windows, iOS, OSX, Android, etc.
420 GetPlatform.isWeb 433 GetPlatform.isWeb
421 434
422 -// Equivalent to the method: MediaQuery.of(context).size.height, but they are immutable. 435 +
  436 +// Equivalent to : MediaQuery.of(context).size.height,
  437 +// but immutable.
423 Get.height 438 Get.height
424 Get.width 439 Get.width
425 440
426 -// Gives the current context of navigator. 441 +// Gives the current context of the Navigator.
427 Get.context 442 Get.context
428 443
429 -// Gives the context of the snackbar/dialog/bottomsheet in the foreground anywhere in your code. 444 +// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.
430 Get.contextOverlay 445 Get.contextOverlay
431 446
432 // Note: the following methods are extensions on context. Since you 447 // Note: the following methods are extensions on context. Since you
433 // have access to context in any place of your UI, you can use it anywhere in the UI code 448 // have access to context in any place of your UI, you can use it anywhere in the UI code
434 449
435 -// If you need a changeable height/width (like browser windows that can be scaled) you will need to use context. 450 +// If you need a changeable height/width (like Desktop or browser windows that can be scaled) you will need to use context.
436 context.width 451 context.width
437 context.height 452 context.height
438 453
439 -// gives you the power to define half the screen now, a third of it and so on.  
440 -//Useful for responsive applications. 454 +// Gives you the power to define half the screen, a third of it and so on.
  455 +// Useful for responsive applications.
441 // param dividedBy (double) optional - default: 1 456 // param dividedBy (double) optional - default: 1
442 // param reducedBy (double) optional - default: 0 457 // param reducedBy (double) optional - default: 0
443 context.heightTransformer() 458 context.heightTransformer()
444 context.widthTransformer() 459 context.widthTransformer()
445 460
446 -/// similar to MediaQuery.of(context).size 461 +/// Similar to MediaQuery.of(context).size
447 context.mediaQuerySize() 462 context.mediaQuerySize()
448 463
449 -/// similar to MediaQuery.of(context).padding 464 +/// Similar to MediaQuery.of(context).padding
450 context.mediaQueryPadding() 465 context.mediaQueryPadding()
451 466
452 -/// similar to MediaQuery.of(context).viewPadding 467 +/// Similar to MediaQuery.of(context).viewPadding
453 context.mediaQueryViewPadding() 468 context.mediaQueryViewPadding()
454 469
455 -/// similar to MediaQuery.of(context).viewInsets; 470 +/// Similar to MediaQuery.of(context).viewInsets;
456 context.mediaQueryViewInsets() 471 context.mediaQueryViewInsets()
457 472
458 -/// similar to MediaQuery.of(context).orientation; 473 +/// Similar to MediaQuery.of(context).orientation;
459 context.orientation() 474 context.orientation()
460 475
461 -/// check if device is on landscape mode 476 +/// Check if device is on landscape mode
462 context.isLandscape() 477 context.isLandscape()
463 478
464 -/// check if device is on portrait mode 479 +/// Check if device is on portrait mode
465 context.isPortrait() 480 context.isPortrait()
466 481
467 -/// similar to MediaQuery.of(context).devicePixelRatio; 482 +/// Similar to MediaQuery.of(context).devicePixelRatio;
468 context.devicePixelRatio() 483 context.devicePixelRatio()
469 484
470 -/// similar to MediaQuery.of(context).textScaleFactor; 485 +/// Similar to MediaQuery.of(context).textScaleFactor;
471 context.textScaleFactor() 486 context.textScaleFactor()
472 487
473 -/// get the shortestSide from screen 488 +/// Get the shortestSide from screen
474 context.mediaQueryShortestSide() 489 context.mediaQueryShortestSide()
475 490
476 /// True if width be larger than 800 491 /// True if width be larger than 800
@@ -488,9 +503,9 @@ context.isLargeTablet() @@ -488,9 +503,9 @@ context.isLargeTablet()
488 /// True if the current device is Tablet 503 /// True if the current device is Tablet
489 context.isTablet() 504 context.isTablet()
490 505
491 -/// Returns a value according to the screen size  
492 -/// can give value for  
493 -/// swatch: if the shortestSide is smaller than 300 506 +/// Returns a value<T> according to the screen size
  507 +/// can give value for:
  508 +/// watch: if the shortestSide is smaller than 300
494 /// mobile: if the shortestSide is smaller than 600 509 /// mobile: if the shortestSide is smaller than 600
495 /// tablet: if the shortestSide is smaller than 1200 510 /// tablet: if the shortestSide is smaller than 1200
496 /// desktop: if width is largest than 1200 511 /// desktop: if width is largest than 1200
@@ -508,7 +523,7 @@ MaterialApp( @@ -508,7 +523,7 @@ MaterialApp(
508 ); 523 );
509 ``` 524 ```
510 525
511 -You will also be able to use your own Middleware within GetObserver, this will not influence anything. 526 +You will also be able to use your own Middleware within `GetObserver`, this will not influence anything.
512 527
513 ```dart 528 ```dart
514 MaterialApp( 529 MaterialApp(
@@ -519,7 +534,8 @@ MaterialApp( @@ -519,7 +534,8 @@ MaterialApp(
519 ); 534 );
520 ``` 535 ```
521 536
522 -You can create Global settings for Get. Just add Get.config to your code before pushing any route or do it directly in your GetMaterialApp 537 +You can create _Global Settings_ for `Get`. Just add `Get.config` to your code before pushing any route.
  538 +Or do it directly in your `GetMaterialApp`
523 539
524 ```dart 540 ```dart
525 GetMaterialApp( 541 GetMaterialApp(
@@ -538,7 +554,9 @@ Get.config( @@ -538,7 +554,9 @@ Get.config(
538 ) 554 )
539 ``` 555 ```
540 556
541 -You can optionally redirect all the logging messages from Get. If you want to use your own favourite logging package and want to capture the logs there. 557 +You can optionally redirect all the logging messages from `Get`.
  558 +If you want to use your own, favourite logging package,
  559 +and want to capture the logs there:
542 560
543 ```dart 561 ```dart
544 GetMaterialApp( 562 GetMaterialApp(
@@ -558,12 +576,12 @@ void localLogWriter(String text, {bool isError = false}) { @@ -558,12 +576,12 @@ void localLogWriter(String text, {bool isError = false}) {
558 576
559 These Widgets allows you to manage a single value, and keep the state ephemeral and locally. 577 These Widgets allows you to manage a single value, and keep the state ephemeral and locally.
560 We have flavours for Reactive and Simple. 578 We have flavours for Reactive and Simple.
561 -For instance, you might use them to toggle obscureText in a TextField, maybe create a custom  
562 -Expandable Panel, or maybe modify the current index in BottomNavigationBar while changing the content  
563 -of the body in a Scaffold. 579 +For instance, you might use them to toggle obscureText in a `TextField`, maybe create a custom
  580 +Expandable Panel, or maybe modify the current index in `BottomNavigationBar` while changing the content
  581 +of the body in a `Scaffold`.
564 582
565 #### ValueBuilder 583 #### ValueBuilder
566 -A simplification of StatefulWidget that works with a "setState" callback that takes the updated value. 584 +A simplification of `StatefulWidget` that works with a `.setState` callback that takes the updated value.
567 585
568 ```dart 586 ```dart
569 ValueBuilder<bool>( 587 ValueBuilder<bool>(
@@ -578,8 +596,8 @@ ValueBuilder<bool>( @@ -578,8 +596,8 @@ ValueBuilder<bool>(
578 ), 596 ),
579 ``` 597 ```
580 598
581 -#### ObxValue  
582 -Similar to ValueBuilder, but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and 599 +####ObxValue
  600 +Similar to [`ValueBuilder`](#valuebuilder), but this is the Reactive version, you pass a Rx instance (remember the magical .obs?) and
583 updates automatically... isn't it awesome? 601 updates automatically... isn't it awesome?
584 602
585 ```dart 603 ```dart
@@ -591,6 +609,214 @@ ObxValue((data) => Switch( @@ -591,6 +609,214 @@ ObxValue((data) => Switch(
591 ), 609 ),
592 ``` 610 ```
593 611
  612 +## Useful tips
  613 +
  614 +
  615 +`.obs`ervables (also known as _Rx_ Types) have a wide variety of internal methods and operators.
  616 +
  617 +> Is very common to _believe_ that a property with `.obs` **IS** the actual value... but make no mistake!
  618 +We avoid the Type declaration of the variable, because Dart's compiler is smart enough, and the code
  619 +looks cleaner, but:
  620 +```dart
  621 +var message = 'Hello world'.obs;
  622 +print( 'Message "$message" has Type ${message.runtimeType}');
  623 +```
  624 +Even if `message` _prints_ the actual String value, the Type is **RxString**!
  625 +
  626 +So, you can't do `message.substring( 0, 4 )`.
  627 +You have to access the real `value` inside the _observable_:
  628 +The most "used way" is `.value`, but, did you know that you can also use...
  629 +
  630 +```dart
  631 +final name = 'GetX'.obs;
  632 +// only "updates" the stream, if the value is different from the current one.
  633 +name.value = 'Hey';
  634 +
  635 +// this weird (and kinda cool) assignment, updates the stream no matter what
  636 +// it takes nulls, or same value... but rebuilds the observers.
  637 +name << 'Hey'; // !
  638 +
  639 +// All Rx properties are "callable" and returns the new value.
  640 +// but this approach does not accepts `null`, the UI will not rebuild.
  641 +name('Hello');
  642 +
  643 +// is like a getter, prints 'Hello'.
  644 +name() ;
  645 +
  646 +/// numbers:
  647 +
  648 +final count = 0.obs;
  649 +
  650 +// you can just most basic operators acts on the property!
  651 +count + 1;
  652 +
  653 +// Watch out! this is only valid if `count` is not final, but var
  654 +count += 1;
  655 +
  656 +// You can also compare against values:
  657 +count > 2;
  658 +
  659 +/// booleans:
  660 +
  661 +final flag = false.obs;
  662 +
  663 +// switches the value between true/false
  664 +flag.toggle();
  665 +
  666 +
  667 +/// all types:
  668 +
  669 +// Sets the `value` to null.
  670 +flag.nil();
  671 +
  672 +// All toString(), toJson() operations are passed down to the `value`
  673 +print( count ); // calls `toString()` inside for RxInt
  674 +
  675 +final abc = [0,1,2].obs;
  676 +// Converts the value to a json Array, prints RxList
  677 +// Json is supported by all Rx types!
  678 +print('json: ${jsonEncode(abc)}, type: ${abc.runtimeType}');
  679 +
  680 +// RxMap, RxList and RxSet are special Rx types, that extends their native types.
  681 +// but you can work with a List as a regular list, although is reactive!
  682 +abc.add(12); // pushes 12 to the list, and UPDATES the stream.
  683 +abc[3]; // like Lists, reads the index 3.
  684 +
  685 +
  686 +// equality works with the Rx and the value, but hashCode is always taken from the value
  687 +final number = 12.obs;
  688 +print( number == 12 ); // prints > true
  689 +
  690 +/// Custom Rx Models:
  691 +
  692 +// toJson(), toString() are deffered to the child, so you can implement override them, and print() the observable directly.
  693 +
  694 +class User {
  695 + String name, last;
  696 + int age;
  697 + User({this.name, this.last, this.age});
  698 +
  699 + @override
  700 + String toString() => '$name $last, $age years old';
  701 +}
  702 +
  703 +final user = User(name: 'John', last: 'Doe', age: 33).obs;
  704 +
  705 +// `user` is "reactive", but the properties inside ARE NOT!
  706 +// So, if we change some variable inside of it...
  707 +user.value.name = 'Roi';
  708 +// The widget will not rebuild!,
  709 +// `Rx` don't have any clue when you change something inside user.
  710 +// So, for custom classes, we need to manually "notify" the change.
  711 +user.refresh();
  712 +
  713 +// or we can use the `update()` method!
  714 +user.update((value){
  715 + value.name='Roi';
  716 +});
  717 +
  718 +print( user );
  719 +
  720 +// this also works.
  721 +user << user.value;
  722 +
  723 +```
  724 +
  725 +#### GetView
  726 +
  727 +I love this Widget, is so simple, yet, so useful!
  728 +
  729 +Is a `const Stateless` Widget that has a getter `controller` for a registered `Controller`, that's all.
  730 +
  731 +```dart
  732 + class AwesomeController extends GetxController {
  733 + final String title = 'My Awesome View';
  734 + }
  735 +
  736 + // ALWAYS remember to pass the `Type` you used to register your controller!
  737 + class AwesomeView extends GetView<AwesomeController> {
  738 + @override
  739 + Widget build(BuildContext context) {
  740 + return Container(
  741 + padding: EdgeInsets.all(20),
  742 + child: Text( controller.title ), // just call `controller.something`
  743 + );
  744 + }
  745 + }
  746 +```
  747 +
  748 +#### GetWidget
  749 +
  750 +Most people have no idea about this Widget, or totally confuse the usage of it.
  751 +The use case is very rare, but very specific: It `caches` a Controller.
  752 +Because of the _cache_, can't be a `const Stateless`.
  753 +
  754 +> So, when do you need to "cache" a Controller?
  755 +
  756 +If you use, another "not so common" feature of **GetX**: `Get.create()`.
  757 +
  758 +`Get.create(()=>Controller())` will generate a new `Controller` each time you call
  759 +`Get.find<Controller>()`,
  760 +
  761 +That's where `GetWidget` shines... as you can use it, for example,
  762 +to keep a list of Todo items. So, if the widget gets "rebuilt", it will keep the same controller instance.
  763 +
  764 +
  765 +#### GetxService
  766 +
  767 +This class is like a `GetxController`, it shares the same lifecycle ( `onInit()`, `onReady()`, `onClose()`).
  768 +But has no "logic" inside of it. It just notifies **GetX** Dependency Injection system, that this subclass
  769 +**can not** be removed from memory.
  770 +
  771 +So is super useful to keep your "Services" always reachable and active with `Get.find()`. Like:
  772 +`ApiService`, `StorageService`, `CacheService`.
  773 +
  774 +```dart
  775 +Future<void> main() async {
  776 + await initServices(); /// AWAIT SERVICES INITIALIZATION.
  777 + runApp(SomeApp());
  778 +}
  779 +
  780 +/// Is a smart move to make your Services intiialize before you run the Flutter app.
  781 +/// as you can control the execution flow (maybe you need to load some Theme configuration,
  782 +/// apiKey, language defined by the User... so load SettingService before running ApiService.
  783 +/// so GetMaterialApp() doesnt have to rebuild, and takes the values directly.
  784 +void initServices() async {
  785 + print('starting services ...');
  786 + /// Here is where you put get_storage, hive, shared_pref initialization.
  787 + /// or moor connection, or whatever that's async.
  788 + await Get.putAsync(() => DbService().init());
  789 + await Get.put(SettingsService()).init();
  790 + print('All services started...');
  791 +}
  792 +
  793 +class DbService extends GetxService {
  794 + Future<DbService> init() async {
  795 + print('$runtimeType delays 2 sec');
  796 + await 2.delay();
  797 + print('$runtimeType ready!');
  798 + return this;
  799 + }
  800 +}
  801 +
  802 +class SettingsService extends GetxService {
  803 + void init() async {
  804 + print('$runtimeType delays 2 sec');
  805 + await 1.delay();
  806 + print('$runtimeType ready!');
  807 + }
  808 +}
  809 +
  810 +```
  811 +
  812 +The only way to actually delete a `GetxService`, is with `Get.reset()` which is like a
  813 +"Hot Reboot" of your app. So remember, if you need absolute persistance of a class instance during the
  814 +lifetime of your app, use `GetxService`.
  815 +
  816 +
  817 +
  818 +
  819 +
594 ## Video explanation of Other GetX Features 820 ## Video explanation of Other GetX Features
595 821
596 822