Appearance
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()