-
Notifications
You must be signed in to change notification settings - Fork 30
Notes about UI architecture
This is a copy/paste from comments on #501, with some editing.
Adamantcheese
Uh, why do we need a base presenter class? Presenters aren't like views and are only attached via a callback. Unless you plan to move everything to implementing this class (which sounds like a waste of time) I think that you can do without this. Also the terminology of "view" is incorrect, because you're passing in a controller instance the only place this is used.
K1rakishou
Well, I don't think I will rewrite the existing code using this thing (maybe in the distant future when I have nothing else to do), but for the new code I'm planning to use it. The Controller/View problem exists because what in Clover is called a Controller should actually be called something like View/Screen. And Controller should actually be something like a presenter. I mean it's the classic MVC but V and C are being the same thing (in Clover). We could leave Controller as is (and pretend it's actually a View/Screen) without renaming anything and just add presenters on top of them.
We just really need to separate the UI logic from the business-logic. Doesn't really matter whether it's MVC or MVP. Clover is already using presenters in some places and, with BasePresenter, I'm just making it more generic.
Adamantcheese
Did some research just to refresh myself on terms; we're definitely using an MVC pattern, just that our terms are different. We've got something more like PLC.
The usual Controller is also named controller for this app. We've got a stack of them that deals with how actions from the views should be processed; if that means changing some data, that action is passed on appropriately, either to the appropriate presenter or to another controller. The usual Model is actually called presenter for this app. Most of the presenters deal with changing the actual data models behind the views, so these are misnamed. The usual View is actually called layout for this app. Layouts tend to be views that have interactivity that should be coupled to the data model (or coupled with other layouts). Views tend to be ones that don't require any user feedback, and are mostly treated as passive elements; this isn't entirely true because MultiImageView violates that generalization, and should actually be called MultiImageLayout.
Basically what I'm getting at is that the Controller is going to make the Layout/Presenter instances, because it has to act as the intermediary between the two. Some controllers though are doing double duty and acting as both a Controller and a Presenter; if there's not a lot going on for the data-model side, that's fine. The same goes for Controller and Layout; basically all the controllers act as double-duty for Layout instances because they're automatically inflated from XML rather than being strictly code. They should all be their own classes that do the inflation and deal with updating elements, but that doesn't really matter most of the time.
Which brings me to my point: to keep in with what currently exists, it would be better for you to not mix and match design patterns for the time being, because that'll just get more messy later on. Your presenter only has one function in it, which can be easily handled by the backing Controller instance. I would rather things remain this way and get a big PR later to update everything at once than do it piecemeal and have to remember that this one instance is made differently than the others.
K1rakishou
Damn and I though why this thing didn't make any sense to me with callbacks going through dozens of classes. Now I kinda understand the flow.
So, If I understand it correctly:
Controller is a navigation element that, when created, shows a view. That view should NOT be created and handled inside the Controller. It should, instead, be created in Layouts (It should create a class that inherits from some kind of ViewGroup and set it to it's internal view variable). Controllers should mostly be empty. Layout is your regular view which takes user input and passes it to presenters. And presenter does all the business logic and then updates the Layout via callbacks.
Basically: Controller -> Layout -> Presenter
Alright. Then I need to create a Layout and move there all the code related to UI. And move presenter instantiation into the layout as well. So that will leave the Controller only with the navigation logic (in this case pretty much empty).
I would like to also suggest the following (for the future): We should also have Repository classes that handle the data coming from the DB/Server/some other place via sources (RemoteSource for server data, LocalSource for DB/Cache etc). All repositories are singletons and can be injected into presenters. Presenters then invoke it's methods and await for the results. Presenters handle all errors that may occur in repositories.
So the flow of the input will be the following: Controller -> Layout -> Presenter -> Repository
If Repository is complex then:
Controller -> Layout -> Presenter -> Repository -> Local Source | +-----> Remote Source
Without a Repository a Presenter will just become a code dump.
I even have an example: https://github.com/Adamantcheese/Kuroba/blob/multi-feature/Kuroba/app/src/main/java/com/github/adamantcheese/chan/ui/controller/settings/ImportExportSettingsController.java https://github.com/Adamantcheese/Kuroba/blob/multi-feature/Kuroba/app/src/main/java/com/github/adamantcheese/chan/core/presenter/ImportExportSettingsPresenter.java https://github.com/Adamantcheese/Kuroba/blob/multi-feature/Kuroba/app/src/main/java/com/github/adamantcheese/chan/core/repository/ImportExportRepository.kt
Adamantcheese
It's more like Presenter <-> Controller <-> Layout, most of the communication goes through the controller in case something else has to happen during a user action/data update. From Floens' own notes (https://github.com/chandevel/Clover/wiki/Clover-ui-infrastrucure), it's modeled off iOS controller infrastructure, which is "MVC", as you can see here. So iOS' "MVC" (https://medium.com/swlh/ios-design-patterns-a9bd07818129) is actually closer to MVP, if you compare the two diagrams (https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93presenter). So the Presenter and Layout can only talk through the controller in this architecture. It's this weird hybrid that was sorta semi realized and was workable for the most part due to the small scale of most layout/controller pairs, which meant they didn't really need a presenter.
Yeah, I would agree that Repository -> Presenter <-> Controller <-> Layout would be the correct architecture. No need for a presenter to talk back to a repository, as it would be input only to the Presenter.
K1rakishou
Ohhh, so in iOS the entry point to a screen is a Controller, not a View (Activity) like in Android. That's why the controller is in the middle and View with Model are on it's sides. Damn, now that I look at it there are even methods like "pushViewController:animated" in iOS documnetation and we have similar in the Clover's Controller class. Was Floens an iOS developer before? I never did touch iOS so I didn't even realize that it was probably adopted from the iOS.
Damn, it's so unusual for me that this thing is in the middle since I'm so used to MVP where everything is going in one direction.