There are several ways in which you can extend remixer:
- Add a new
DataType
:- Create a
ValueConverter
for theDataType
- Set as default layoutIDs by calling
DataType.setLayoutIdForVariableType(Class<? extends Variable>, int)
- Register it at
Application.onCreate()
time- can be done in
RemixerInitialization.initRemixer()
if you're adding it at the Remixer level (forking/contributing)
- can be done in
- Note: At the time only forks/contributions can add annotation processing support for new DataTypes. If it proves necessary we'll write extension points for the annotation processor.
- Create a
- Implement a new
RemixerWidget
- Optionally, set it as a default Layout Id for a
DataType
/Variable class
combination by callingDataType.setLayoutIdForVariableType
. You can do it inRemixerInitialization.initRemixer()
if forking/contributing.
- Optionally, set it as a default Layout Id for a
Notice that if you plan to use the Firebase Remote Controller functionality, you need to replicate this work in the material-remixer-js and material-remixer-remote-web projects as well. It is out of scope for this document to explain how to do it in those projects.
In order to add a new data type to Remixer, you need to construct a static instance of the DataType class...
public static final DataType<RT, ST> MY_NEW_TYPE = new DataType<>(
"myNewType",
RT.class,
ST.class,
new MyNewTypeValueConverter("myNewType"));
... and register it as a RemixerType somewhere that only gets called once (preferably during your Application.onCreate()
)...
public class MyApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Remixer.registerDataType(MY_NEW_TYPE);
}
}
Now let's dissect the first statement, the new DataType<>(...)
:
- It has two generic parameters, RT and ST, the RuntimeType and the SerializedType. The former is used for callbacks during runtime, and the latter is used to serialize, store data and (potentially) sync it to Firebase. They can be exactly the same type, and they usually are.
- It has a unique identifier string, in the example it's "myNewType". It can be whatever you want but current identifier strings are "boolean", "color", "number" and "string".
- You need to write a subclass of
ValueConverter
which converts between the RuntimeType and the SerializedType and performs other serialization-related tasks.
Now you can use it with any of the variable classes using the appropriate Builder. Just make sure to call setDataType(MY_DATA_TYPE)
and you're done.
Variable subclasses represent constraints on what values the variable can take.
- Create a subclass of Variable.
- Override its
checkValue(T)
method. - Override its
getSerializableConstraints()
method with a new constant constraint string that is unique to this class. - Add new fields to
StoredVariable
representing new data required to represent the new variable subclass. - Make sure you update
ValueConverter
'sfromVariable(Variable<?>)
,serialize(StoredVariable<SerializableType>)
anddeserialize(JsonElement)
methods to match the new fields.
If you add a new type or variable you may want to make it easier to use by adding annotation support. This is easy if you are forking or contributing to the android remixer repository, but otherwise we do not currently offer a way to extend the annnotation processor. We may if this becomes a problem down the line.
- Subclass
MethodAnnotation
to handle your new annotation classes. - Add a new enum item per new annotation you're supporting to
SupportedMethodAnnotation
- Add lots of tests, these errors are hard to debug, so please do your best to keep coverage high.
Note: Remixer relies on inflating widgets by layout id, so these cannot be pure-java, they need to have a layout resource associated with them.
- Write a new class that extends
android.view.ViewGroup
(usually eitherLinearLayout
orRelativeLayout
) and implementsRemixerWidget
- Add a new layout resource whose element is of the class you just created.
- Optionally, set it as a default Layout Id for a
DataType
/Variable class
combination by callingDataType.setLayoutIdForVariableType(Class<? extends Variable>, int)
. You can do it inRemixerInitialization.initRemixer()
if forking/contributing.
Even if you do not set it as a default layout anywhere, you can still force to use it by setting the layoutId property on a variable.