Closed jordond closed 5 years ago
Wow, that looks quite promising. I guess it's just a bit out of the current scope.
I created some issues (#69, #70 and #71) I consider to be of higher importance considering the 5.0.0 release. It already basically deprecates the whole library and I don't want to overwhelm possible migrating users with too many features.
I still think plugin support would be a great addition, I'd just schedule it for the next major release. And since as much as possible should be moved to a separate module, I'd still like to have a simple debug mode for Eiffel's core that we discussed in #67.
Luckily I came prepared ;) #72. In my spare time, I may continue to explore the idea of creating a desktop client to monitor the state.
Sounds good. 🙂
I was also using live templates but found it hugely annoying that they are removed on every Android Studio update.
Proposal
Settle in, this is gonna be a long one.
Note: I will be providing samples in this PR, but there are more detailed comments in the code.
References #60 and replaces #68.
I have added the ground work for a basic "Plugin" functionality for Eiffel. Right now the only plugin I have created is a
LoggingPlugin
which will logEvent
's to the logcat (more on that below).EiffelPlugin
Right now the
EiffelPlugin
interface is very basic.The
name
property is currently unused, but my theory behind it was some way to identify the plugin, maybe for logging purposes.The
onEvent
function is where the magic happens. Each plugin will be able to react to everyEvent
that is fired off by theEiffelViewModel
. This approach is very basic, and perhaps in the future we could add the ability to block or have some kind of "continuation" so theEiffelPlugin
could observe the before/after of an event.We may even want to pass along the
scope
,dispatch
from theEiffelViewModel
so that we can hijack the state/actions. In my head I was thinking like a time-travel debugger of sorts.The
dispatcher: String
is just a tag of the class that dispatched the action. Perhaps a better approach would be to haveEvent
contain the tag instead.Event
Right now there are a few supported events that can be fed to the plugins:
Most of these are pretty self-explanatory, but if you need more info, again there are detailed comments in the code.
I am open to adding/removing/modifying these
Event
's, this is just what I came up with for this PR.Dispatcher
The dispatcher controls the way the
Event
's are dispatched to the plugins. I have a basic implementation, but I'm not exactly in-love with it at its current state. It feels dirty accessing the plugins via the globalEiffel
but maybe its fine. Again open to feedback/suggestion for it.Packaged plugins
I have included a
LoggerPlugin
as a packaged plugin. Right now it is not opt-in, and will always be added to the list of plugins. It's also in the same package aseiffel
, so we could even move it to it's own module.I have created a
DefaultLoggerPlugin
and aReleaseLoggerPlugin
. The latter is useful for production mode. Say you overrideEiffelViewModel.debug
to betrue
, and you forget to remove it before pushing the code out to production. The release logger will take care of that by doing nothing when it's invoked.The
ReleaseLoggerPlugin
is opt-in and you can see an example of that in the sample app below.The
Logger
is the interface from the previous PR, just a way to customize how the event is logged. In the sample app, I have it setup to useTimber
.The
transform
is where the magic happens. Say you want to create a logger that can log to crashlytics, or some other custom solution. Well withtransform
you can take theEvent
and transform it to any object you need. There are of course some sensible defaults provided.Future plans
The whole reason why I decided to tackle a plugin approach was because of another library I saw called Suas. I noticed they had a companion app for the desktop that would display all the store events. So I looked into their source for both the android side, and the desktop side (they use TypeScript and Electron, both I've used extensively). And it looks doable. At least from the current standpoint of viewing the
State
, andAction
's.You can see their monitor here
So plugins I'm currently envisioning are:
eiffel-plugin-monitor
LoggerPlugin
?eiffel-plugin-logger-firebase
LoggerPlugin
that logs certainEvent
's to Firebase's Event's featureEvent.Error
that would log as a non-fatal error to crashlyticsSample app
It's not complete, but I have created a very basic sample app that showcases the new
EiffelPlugin
andLoggerPlugin
features. It's on a different branch and you can see it hereNotable points of interest are the
release/ReleaseApp.kt
, anddebug/DebugApp.kt
. Then there is a basicFragment
andEiffelViewModel
.I will probably expand on it more later.
Here is an example of the log output:
It's marked as an error because in
DebugApp
I have overridden it to always log toTimber.e
(for better visibility in the logcat)`.Closing
If you've made it this far congrats! I know your busy, but I'd appreciate your feedback/criticism/ideas. If we want to get logging in before we get the plugin architecture in, then I can extract it and create a new PR.