How would you do that? If I understand MVI à la Hannes Dorfmann correctly, all the business logic should happen in the rx streams outside the reducer. To make these streams generic, they emit intents, which are basically simple named actions, common to all screens, that should be performed on the state. The reducer is then the part that "adapts" this to our specific state by applying the action to the specific state. Obviously this can't possibly scale because the reducer keeps growing with the number of intents. Not only that, if the intents are in any way non-trivial we have unnecessary code duplication as well. The MVI-reducer abstracts away the actions, which is backwards. We really want to abstract the data.
Here I experimented with something more reusable where the business logic is generic over the view and state. The presenter then simply consists of mappings from the specific state to the abstract one by passing accessor functions:
https://github.com/tschuchortdev/Commit-Strip-Reader/blob/stream_arch/app/src/main/java/com/tschuchort/readerforcommitstrip/UseCases.kt This is far from usable but perhaps it can give you some ideas to cook up something better. The
main conceptual difference to MVI is that instead of "intents" I use generic functions that are executed by a hidden reducer.
I'm not sure how a truly composable solution would even look due to the disconnect of view and presenter. But for the business logic I think we would need to make each use case have it's own state machine and then adapt that through composition. In android this is even harder due to the issues with process death, debouncing and navigation.