Settings
Extensions often need ways for users to change how they behave. You can build a settings page that shows up in the extension detail screen or even add items to the main app settings.
Extension vs Global Settings
In most cases, you should prefer extension settings over app settings. Otherwise, the settings screen would quickly become cluttered. Only if your extension adds a major feature or requires frequent changes to the settings might it make sense to include it in the app's main settings.
Extension Settings
Manifest Setup
If you want to define extension-specific settings, you must first tell Xed-Editor by adding this to your manifest.json:
"hasSettings": trueCreating a Settings UI
In your main class that extends ExtensionAPI, you can override SettingsContent. This is where you build your UI using Jetpack Compose.
Please note that Xed-Editor already embeds your SettingsContent() into a PreferenceLayout that includes a top bar displaying your extension's name. Therefore, you should not use an additional PreferenceLayout:
class Main(context: ExtensionContext) : ExtensionAPI(context) {
@Composable
override fun SettingsContent() {
// Build your UI here
PreferenceGroup(heading = "General") {
PreferenceSwitch(
label = "Auto save",
checked = MySettings.autoSave,
onCheckedChange = { MySettings.autoSave = it }
)
SteppedValueSlider(
label = "Save interval",
min = 1,
max = 60,
default = MySettings.interval,
onValueChanged = { MySettings.interval = it }
)
}
PreferenceGroup(heading = "Advanced") {
NextScreenCard(
label = "Advanced configuration",
description = "Configure internal parameters",
route = "advanced_settings"
)
}
}
}TIP
It is strongly recommended to use the provided UI components for settings rather than creating your own, in order to ensure consistency with the app's native user interface. For more information, please refer to the Settings UI Components guide.
Settings Storage API
Xed-Editor gives you a simple way to save and load settings. All extension settings are separated from other extensions, so you don't have to worry about them messing with your data.
Manual Usage
You can read and write values directly through the context:
// Save a value
context.settings.putBoolean("show_line_numbers", true)
// Read a value
val show = context.settings.getBoolean("show_line_numbers", false)For each of the 5 supported data types there are dedicated methods:
putString/getStringputBoolean/getBooleanputInt/getIntputFloat/getFloatputLong/getLong
The Delegate Pattern (Best Practice)
For a cleaner code, you can use delegates. Create a dedicated settings object and use context.settings.delegate.
object MySettings {
var showLineNumbers by context.settings.delegate("show_line_numbers", true)
var themeName by context.settings.delegate("theme_name", "Dark")
}// Now you can use them like normal variables:
// Save a value
MySettings.showLineNumbers = true
// Read a value
if (MySettings.showLineNumbers) {
// ...
}Global Settings
In order to add your own categories and screens to the main app settings, you can use the SettingsRegistry.
You first need to register a category, which is then shown in the main settings page. The route property is used to navigate to your implemented screen.
In order for it to work, you must also register a route in the Settings. Analog to the NavGraphBuilder Compose API, a DynamicRoute has three possible arguments:
route: String The id of the route you want to register (has to match therouteproperty of the category).arguments: List<NamedNavArgument> A list of arguments that the route accepts ( optional, for settings often not necessary).content: @Composable (NavController, NavBackStackEntry) -> Unit The composable content of the route, taking theNavControllerand theNavBackStackEntryas parameters.
override fun onLoad() {
val category = SettingsCategory(
label = context.resources.getString(R.string.my_extension_label),
description = context.resources.getString(R.string.my_extension_desc),
icon = Icon.ExternalResource(R.drawable.ic_extension, context.resources),
route = "my_extension_settings"
)
SettingsRegistry.registerCategory(category)
val route = DynamicRoute(
route = "my_extension_settings",
content = { navController, backStackEntry ->
MySettingsScreen()
}
)
SettingsRegistry.registerRoute(route)
}Similarly to the extension-specific settings, you can also use the Settings Storage API to save and load values in MySettingsScreen().
INFO
Remember to unregister these in onDispose with unregisterCategory and unregisterRoute to keep the app clean.