fluttery_framework 2.1.0 copy "fluttery_framework: ^2.1.0" to clipboard
fluttery_framework: ^2.1.0 copied to clipboard

Provides all the functions and features needed for a typical production app.

Fluttery Framework #

codecov CI Pub.dev GitHub stars Last Commit

A Flutter Framework's Framework #

Fluttery_Framework Allows for easier and, dare I say, faster development and better maintainability. No 're-inventing of the wheel' using already built-in capabilities and features offered by Flutter itself. Accommodating and Integrated features:

  • Error Handling
  • System Preferences
  • App Notifications
  • A Better Menu Bar
  • Device Event Handling
  • Date picker
  • App Color picker
  • Dialog Boxes
  • Customizable Bottom Bar
  • Loading Screen
  • Time Zones

Installing #

I don't like the version number suggested in the 'Installing' page. Instead, always go up to the 'major' semantic version number when installing this library package. This means always trailing with two zero, '.0.0'. This allows you to take in any 'minor' versions introducing new features as well as any 'patch' versions that involves bugfixes. Example, to install version 7.9.2, use 7.0.0. Thus, the bug fix, 7.9.2, will be installed the next time you 'upgrade' the dependencies.

  1. patch - bugfixes
  2. minor - Introduced new features
  3. major - Essentially made a new app. It's broken backwards-compatibility and has a completely new user experience. You won't get this version until you increment the major number in the pubspec.yaml file.

And so, in this case, add this to your package's pubspec.yaml file:

dependencies:
   fluttery_framework: ^1.0.0

For more information on version numbers: The importance of semantic versioning.

Note, in fact, this package serves as a 'wrapper' for the core package:

StateX Pub.dev GitHub stars Last Commit #

Example Code: #

The Counter App
import 'package:fluttery_framework/view.dart';

import 'package:fluttery_framework/controller.dart';

void main() => runApp(MyApp());

class MyApp extends AppStatefulWidget {
  MyApp({Key? key}) : super(key: key);

  @override
  AppState createAppState() => View();
}

class View extends AppState {
  View()
      : super(
    title: 'Flutter Demo',
    home: const MyHomePage(),
    debugShowCheckedModeBanner: false,
    theme: ThemeData(
      primarySwatch: Colors.green,
    ),
  );
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, this.title = 'Flutter Demo Home Page'})
      : super(key: key);
  // Fields in a StatefulWidget should always be "final".
  final String title;
  @override
  State createState() => _MyHomePageState();
}

class _MyHomePageState extends StateX<MyHomePage> {
  _MyHomePageState() : super(Controller()) {
    con = controller as Controller;
  }
  late Controller con;

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      title: Text(widget.title),
    ),
    body: Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          const Text('You have pushed the button this many times:'),
          Text(
            '${con.counter}',
            style: Theme.of(context).textTheme.headline4,
          ),
        ],
      ),
    ),
    floatingActionButton: FloatingActionButton(
      /// Try this alternative approach.
      /// The Controller merely mimics the Flutter's API
      //         onPressed: con.onPressed,
      onPressed: () => setState(con.incrementCounter),
      tooltip: 'Increment',
      child: const Icon(Icons.add),
    ),
  );
}

class Controller extends StateXController {
  factory Controller() => _this ??= Controller._();
  Controller._()
      : model = _Model(),
        super();

  static Controller? _this;
  final _Model model;

  /// You're free to mimic Flutter's own API
  /// The Controller is able to talk to the View (the State object)
  void onPressed() => setState(() => model._incrementCounter());

  int get counter => model.integer;

  /// The Controller knows how to 'talk to' the Model.
  void incrementCounter() => model._incrementCounter();
}

class _Model {
  int get integer => _integer;
  int _integer = 0;
  int _incrementCounter() => ++_integer;
}

Name Generator App

import 'package:english_words/english_words.dart' show generateWordPairs;

import 'package:flutter/material.dart' hide runApp;

import 'package:fluttery_framework/view.dart'
    show AppStatefulWidget, AppState, Colors, runApp, StateX;

import 'package:fluttery_framework/controller.dart' show StateXController;

void main() => runApp(NameApp());

class NameApp extends AppStatefulWidget {
  NameApp({Key? key}) : super(key: key);

  @override
  AppState createAppState() => MyApp();
}

class MyApp extends AppState {
  factory MyApp() => _this ??= MyApp._();
  MyApp._()
      : super(
    title: 'Startup Name Generator',
    home: const RandomWords(),
    theme: ThemeData(
      primaryColor: Colors.white,
    ),
    debugShowCheckedModeBanner: false,
  );
  static MyApp? _this;
}

class RandomWords extends StatefulWidget {
  const RandomWords({Key? key}) : super(key: key);

  @override
  State createState() => _RandomWordsState();
}

class _RandomWordsState extends StateX<RandomWords> {
  _RandomWordsState() : super(_Controller()) {
    con = controller as _Controller;
  }
  late _Controller con;

  final TextStyle _biggerFont = const TextStyle(fontSize: 18.0);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Startup Name Generator'),
        actions: <Widget>[
          IconButton(
              icon: const Icon(Icons.list),
              onPressed: () {
                pushSaved(context);
              }),
        ],
      ),
      body: _buildSuggestions(),
    );
  }

  Widget _buildSuggestions() {
    return ListView.builder(
      padding: const EdgeInsets.all(16.0),
      itemBuilder: (context, i) {
        // Add a one-pixel-high divider widget before each row in theListView.
        if (i.isOdd) return const Divider();
        final index = i ~/ 2;
        // If you've reached the end of the available word pairings...
        if (index >= con.length) {
          // ...then generate 10 more and add them to the suggestions list.
          con.addAll(10);
        }
        return buildRow(index);
      },
    );
  }

  void pushSaved(BuildContext context) {
    Navigator.of(context).push(
      MaterialPageRoute<void>(
        builder: (BuildContext context) {
          final Iterable<ListTile> tiles = this.tiles;

          List<Widget> divided;

          if (tiles.isEmpty) {
            divided = [];
          } else {
            divided = ListTile.divideTiles(
              context: context,
              tiles: tiles,
            ).toList();
          }

          return Scaffold(
            appBar: AppBar(
              title: const Text('Saved Suggestions'),
            ),
            body: ListView(children: divided),
          );
        },
      ),
    );
  }

  Widget buildRow(int? index) {
    if (index == null || index < 0) index = 0;

    String something = con.something(index);

    final alreadySaved = con.contains(something);

    return ListTile(
      title: Text(
        something,
        style: _biggerFont,
      ),
      trailing: Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          con.somethingHappens(something);
        });
      },
    );
  }

  Iterable<ListTile> get tiles => con.mapHappens(
        (String something) {
      return ListTile(
        title: Text(
          something,
          style: _biggerFont,
        ),
      );
    },
  );
}

class _Controller extends StateXController {
  // Supply only one instance of this Controller class.
  factory _Controller() => _this ??= _Controller._();

  static _Controller? _this;

  _Controller._() {
    model = _Model();
  }

  late _Model model;

  int get length => model.length;

  void addAll(int count) => model.addAll(count);

  String something(int index) => model.wordPair(index);

  bool contains(String something) => model.contains(something);

  void somethingHappens(String something) => model.save(something);

  Iterable<ListTile> mapHappens<ListTile>(ListTile Function(String v) f) =>
      model.saved(f);
}

class _Model {
  final List<String> _suggestions = [];

  int get length => _suggestions.length;

  String wordPair(int? index) {
    if (index == null || index < 0) index = 0;
    return _suggestions[index];
  }

  bool contains(String? pair) {
    if (pair == null || pair.isEmpty) return false;
    return _saved.contains(pair);
  }

  final Set<String> _saved = {};

  void save(String? pair) {
    if (pair == null || pair.isEmpty) return;
    final alreadySaved = contains(pair);
    if (alreadySaved) {
      _saved.remove(pair);
    } else {
      _saved.add(pair);
    }
  }

  Iterable<ListTile> saved<ListTile>(ListTile Function(String v) f) =>
      _saved.map(f);

  Iterable<String> wordPairs([int count = 10]) => _makeWordPairs(count);

  void addAll(int count) => _suggestions.addAll(wordPairs(count));
}

Iterable<String> _makeWordPairs(int count) =>
    generateWordPairs().take(count).map((pair) => pair.asPascalCase);
Other Dart Packages

packages Other Dart packages from the author can also be found at Pub.dev