Skip to content

Portfolio Platform Flutter App – 2 – Code Structure

Portfolio Platform Flutter App with BLOC

Here you have some code snippets of my Portfolio Platform Flutter App. I’ve written about the architecture and the software development approach in the previous post. The full code will be available in this package: https://programtom.com/dev/product/portfolio-platform-php some time in the future (currently 07.01.2022 – not). I’ll publish several versions between the beginning and the version that is included in the package.

Portfolio Platform Model

For the Version 1 The Model will be only one.

class Profile {
  int id;
  String name;
  String? summary;
  String picture;

  Profile({
    required this.id,
    required this.name,
    this.summary,
    required this.picture,
  });
Profile.fromJson(Map<String, dynamic> json)
    : this(
        id: json['id'] as int,
        name: json['name'],
        summary: json['summary'],
        picture: json['picture'],
      );
}

The summary field is nullable, because it will be displayed in the details screen and this will optimize the list screen. There is a general principle – never load more data – greater than – what you show – at least at the initial moment – to the user.

States

The states of the App will be derived from the Screens.

abstract class PPBlocStates {
  Stream<String?> get message;

  Stream<PaginatedList<Profile>> get profiles;
}

The ideas here is the list display a list of profiles with returns also the total count. Depending on the offset of the query – there may be more items or not. It also my be – query from the start (pull to refresh).

Events

abstract class PPBlocEvents {
  void loadPage(int offset, {bool force = true});
}

To integrate with more code from the rx_bloc ecosystem, I’ll most probably integrate also the rx_bloc_list package.

Blocs

I love code generators, I’ve written such product myself – the Generator App. Prime Holding have a lot of packages that Generate Code for free. At the time of writing this article I didn’t had enough time to understand and learn them all, because my main focus is not the bloc. In general it is good idea to know what is going on. The BloC in their ecosystem is a sum of several items with annotations, packages and plugins – events, states, extensions and so on. The result in my research so far – is something like this (several parts of it – generated):

class PPBloc extends RxBlocBase implements PPBlocStates, PPBlocEvents, PPBlocType {
static const int LIMIT = 10;
final _paginatedList = BehaviorSubject<PaginatedList<Profile>>.seeded(
PaginatedList<Profile>(
list: [],
pageSize: LIMIT ,
),
);
String? messageCache;
PPNetworkRepository ppNetworkRepository;

PPBloc(this.ppNetworkRepository) {
loadPage(0);
}

@override
Stream<String?> get message => Future<String?>.value(messageCache).asStream();

@override
PPBlocEvents get events => this;

@override
PPBlocStates get states => this;

@override
Stream<PaginatedList<Profile>> get profiles => _paginatedList.stream;

@override
void dispose() {
_paginatedList.close();
super.dispose();
}

@override
void loadPage(int offset, {bool force = false}) =>
_loadPage(offset, force: force);
}

Extensions/Data Access

The Bloc has a binding role. What happens in concrete events is what is the true business logic. It may grab stuff from different Data Sources, process data, do optimizations and so on. To be testable, they are extracted to Extension methods like this:

extension LoadPageExt on PPBloc {
  void _loadPage(int offset, {bool force = true}) {
    var listURL = "http://~/Portfolio_Platform/listof_items.alabala";
    var uri = Uri.parse(listURL + "?limit="+LIMIT+"&offset=" + offset.toString());
    http.get(uri).then((response) {
      Map<String, dynamic> dataResult = json.decode(response.body);

      if (force) {
        _paginatedList.value = PaginatedList<Profile>(
          list: [],
          pageSize: LIMIT ,
        );
      }
      var snapshot = dataResult["list"] != null
          ? (asList(dataResult["list"]) as List)
              .map((i) => Profile.fromJson(i))
              .toList()
          : <Profile>[];

      _paginatedList.add(PaginatedList(
          pageSize: LIMIT , list: snapshot, totalCount: dataResult['count']));
    });
  }

In the next following articles, I’ll publish several – minimally working – phases of the application. It will evolve into a fully functional app – with most of the best practices and patterns.

Leave a Reply

Your email address will not be published.