Skip to content

Reactive Plugin - Android SampleApp

The Domain module

PlatformHub itself is completely decoupled from any plugin implementation outside the use of the few public interfaces available in the SDK, and can be used with any app and any programming architecture.

However, the Redux implementation used by the sample app and its plugins is the recommended approach for interacting with PlatformHub in your app and plugins as it provides a powerful reactive system to keep your data and UI up-to-date.


The Plugin

A Domain plugin might receive a query

kotlin
override fun onReceive(message: BaseMessage.Query) = queryHandler[message]
    .onQuery(message, if (store.initialised) store else null)

A Domain plugin might subscribe to events

kotlin
override fun subscribeOnStartup(subscription: SharedFlow<EventStreamOutput>, eventStream: BaseMessage.EventStream) {
    subscription.onEach { result ->
        withContext(Dispatchers.Main) {
            val handler = eventHandler[Events.valueOf(eventStream.messageName)]
            handler?.onEvent(
                result,
                context,
                if (store.initialised) store else null
            )
        }
    }.launchIn(coroutineScope + Dispatchers.Default)
}

A Domain plugin might publish events

kotlin
override fun publish(eventStream: BaseMessage.EventStream): SharedFlow<EventStreamOutput> {
    return when (eventStream.messageName) {
        Events.AccountListLoaded.name -> domainAccountListSharedFlow
        Events.AccountDetailsLoaded.name -> domainAccountDetailsSharedFlow
        Events.AccountTransactionsLoaded.name -> domainAccountTransactionsSharedFlow
        Events.PrimaryAccountUpdated.name -> domainPrimaryAccountSharedFlow
        else -> MutableSharedFlow()
    }
}

The Actions

A Domain module handles logic through Actions

kotlin
internal sealed class AccountListAction : Action {
    object Fetch : Action
    object Loading : Action
    data class Loaded(val data: List<Account>) : Action
}

The SideEffects

Some Actions may have a SideEffect which will return a new Action based on the side effect

kotlin
internal class AccountSideEffect(private val plugin: DomainModelPlugin) :
    SideEffect<DomainPluginStateGroup> {
    override fun invoke(
        store: Store<DomainPluginStateGroup>,
        action: Action,
        next: Next<DomainPluginStateGroup>
    ): Action = when (action) {
        //
        is AccountListAction.Fetch -> {
            val query = DomainModelPlugin.Queries.FetchAccountList
            plugin.send(BaseMessage.Query(query.name, pluginName = SAMPLE_DATA_PLUGIN_NAME))
            AccountListAction.Loading
        }
        //
        is AccountDetailsAction.Get -> {
            val payloadJson = "{ \"accountNumber\": ${action.number} }".trimIndent()
            val query = DomainModelPlugin.Queries.GetAccountDetails
            plugin.send(
                BaseMessage.Query(
                    messageName = query.name,
                    payload = JSONObject(payloadJson),
                    pluginName = SAMPLE_DATA_PLUGIN_NAME
                ),
            )
            AccountDetailsAction.Loading
        }
        // [...]
        else -> next(store, action)
    }
}

The Reducer

Actions are reduced and update States

kotlin
internal fun reducer(state: DomainPluginStateGroup, action: Action): DomainPluginStateGroup =
    when (action) {
        //
        is AccountListAction.Loading -> state.update(
            AccountState(isLoading = true)
        )
        //
        is AccountListAction.Loaded -> state.update(
            AccountState(false, action.data)
        )
        // [...]
        else -> state
    }

The States

States contain the information the Domain module needs

kotlin
internal data class AccountState(
    override val isLoading: Boolean = false,
    val data: List<Account> = emptyList(),
) : State()