Skip to content
This repository has been archived by the owner on Oct 19, 2022. It is now read-only.

Developer Documentation

Daniel edited this page Nov 4, 2019 · 7 revisions

The OX COI Messenger is a cross platform app for Android and iOS.

Information

Structure

Architecture

OX COI Messenger uses the BloC pattern as base for the app architecture. As data provider repositories are used. Within the repositories calls to the below mentioned plugin are made to fetch the data.

Architecture

Widget

Widgets are UI components. Widgets have the following properties:

  • Never access data directly. Always use a BloC to get / set data
  • Only contain UI code and the usage of setState should get minimized
    • setState is allowed if a widget maintains states which are only relevant for the UI. E.g. setState is allowed if a Widget contains a button which only folds or unfolds UI. As soon as any data is modified a BloC must be used
  • Does not contain any async calls, except for native plugin calls

BloC

BloCs (Business logic components) contain the logic of the app. This layer connects the data delivered by the plugin / core with the UI. A BloC should deliver filtered and adjusted data the UI can use. There should be no need for the UI to adjust data delivered by a BloC.

Blocs have the following properties:

  • Should be initialized without parameters
    • All values (also initial values) should be added via events
  • Get input from the user or another source via events
  • Deliver an output stream of states, interested parties can subscribe to
  • Accesses all data through repositories or data objects. Saving data directly in the BloC should be avoided, but it's allowed if required
  • Can listen to repository events
    • If a listener is registered it has to be unregistered in the dispose method
  • Should only listen directly to plugin / core events if no repository could be used
  • Can perform async calls
  • Allowed to perform plugin / core calls
  • Can dispatch events to adjust the state of the BloC if self or of other BloCs
  • Should not expose any methods, as only events should input data and states should be used as output
    • Exceptions are okay if required

Within the app the libraries https://pub.dartlang.org/packages/bloc and https://pub.dartlang.org/packages/flutter_bloc are used to avoid boilerplate code. Dart streams are extend by the usage of https://pub.dartlang.org/packages/rxdart.

Repository

Repositories have the main responsibility to manage data from the core which should get propagated to interested parties. Repositories are provided by the RepositoryManager. Repositories have the following properties:

  • Exactly one item type per repository (e.g. contact or message)
    • A repository should only be used if multiple objects of the given type can and should exists. Every object in a repository needs a unique id. If a type doesn't match the requirements to be stored in a repository, it should be constructed as DataManager (see below)
  • One or more repositories of one type can exists
  • Contains a list of entries of the given type
  • Can perform async calls
  • Allowed to perform plugin / core calls
  • Delegates listener registration / deregistration to the core and events back to interested parties
    • Users of the repository can add / remove listeners for different event types. If a listener for the event type exists it is reused (managed by the core). Doing this we minimize the connections between app and plugin / core
    • If the last interested party / user of an event type unsubscribes the listener connection is automatically closed (managed by the core)
  • Provides a stream of core events to interested parties
    • Every user of the repository can register for events
    • Every core event the repository has subscribed to is delivered on this stream. The user has to determine if the event is relevant
    • The repository itself is also an interested party and can provide a concrete implementation for given events. Doing this is an additional task, the event will also be delivered to all interested parties

Data Manager

Data Managers are used for single objects or objects which only exist a few times within the app. Data Managers have the following properties:

  • Can contain any data or logic
  • Should provide a way to manage object creation and object management
    • If only one object can exist at a time a Singelton should be used
    • If more than one object can exist some internal logic (e.g. a list or map) should be implemented
  • Can perform async calls
  • Allowed to perform plugin / core calls
  • Should provide a sync (not async) way to load data if possible
  • Can listen directly to plugin / core events

Communication between app and plugin

To communicate with IMAP / SMTP servers, OX COI Messenger uses the Delta Chat Core (https://github.com/deltachat/deltachat-core). The DCC provides the data internally used.

Communication between app and plugin

OX Coi Messenger provides an user interface for Android and iOS. It uses the Delta Chat Core Plugin, which consists of two parts, one which provides the actual API to the Flutter app and one which provides the link to the platform specific implementation. The platform specific implementation (a JNI interface for Android and Swift bridging for iOS) is used to access the Delta Chat Core (DCC) which is written in Rust and is used on both platforms. DCC is a library for IMAP/SMTP based chats.

The OX COI Messenger and most of the Delta Chat Core Plugin is written in house as open source software. The Delta Chat Core is an open source project maintained by the DCC-Team on GitHub (https://github.com/deltachat/deltachat-core). Open-Xchange is also contributing to Delta Chat Core.