Skip to Content
Settings

Settings

ZwyLib provides a small framework for declaring persistent, per-plugin settings and binding them directly to exteraGram’s settings-screen components (Input, Selector, Switch), so you don’t have to wire storage and UI together by hand.

Getting Started

Declare each setting once as a SettingEntry, then bind it to a settings-screen component when building your plugin’s preferences:

# ... metadata and zwylib import ... from zwylib import SettingEntry class MySettings: greeting = SettingEntry("greeting", "Hello!", icon="msg_edit") notify = SettingEntry("notify", True, icon="msg_notifications") class MyPlugin(BasePlugin): def create_settings(self): return [ MySettings.greeting.as_input(text="Greeting text"), MySettings.notify.as_switch(text="Show notifications"), ]

Reading and writing a setting from anywhere in your plugin is then just:

current = MySettings.greeting.get() MySettings.greeting.set("Hi there!")

zwylib.SettingEntry

SettingEntry(key: str, default: Any, icon: Optional[str] = None)

Describes a single named setting belonging to the calling plugin. The owning plugin ID is inferred automatically from the call stack at construction time, so SettingEntry instances should be created at your plugin’s module level (not inside a function called from elsewhere).

Constructor Arguments

  • key (str): Unique key identifying this setting within your plugin’s settings.
  • default (Any): Value returned by get when the setting hasn’t been set yet.
  • icon (Optional[str], default None): Drawable resource name used when this entry is bound to a settings-screen component via as_input, as_selector, or as_switch.

Methods

get

SettingEntry.get() -> Any

Returns the current value of this setting, or default if it hasn’t been set.


safe_get

SettingEntry.safe_get( factory: (Any) -> _T, bulletin_text: str = None, log_text: str = None ) -> _T

Reads the setting and passes it through factory (e.g. int, float, a custom parser), falling back to factory(default) and logging the error if either the read or the conversion fails.

Parameters

  • factory ((Any) -> _T): Function used to convert the raw stored value into the desired type.
  • bulletin_text (str, optional): If provided, shown as an error bulletin when the conversion fails.
  • log_text (str, optional): Custom message logged when the conversion fails. Defaults to a generic message naming the setting’s key.

Example

timeout = S.autoupdate_timeout.safe_get(int, bulletin_text="Invalid timeout, using default.")

set

SettingEntry.set(value: Any) -> None

Persists a new value for this setting and reloads the plugin’s settings screen.

Parameters

  • value (Any): The new value to store.

Example

S.enable_autoupdates.set(False)

as_input

SettingEntry.as_input(**kwargs) -> Input

Builds a ui.settings.Input component bound to this entry — key, default, and icon (if set) are filled in automatically.

Parameters

  • **kwargs: Any other Input constructor arguments (text, subtext, on_change, etc.).

Example

S.autoupdate_timeout.as_input(text="Update check interval (seconds)")

as_selector

SettingEntry.as_selector(**kwargs) -> Selector

Builds a ui.settings.Selector component bound to this entry — key, default, and icon (if set) are filled in automatically.

Parameters

  • **kwargs: Any other Selector constructor arguments (text, items, on_change, etc.).

Example

S.theme.as_selector(text="Theme", items=["Light", "Dark", "System"])

as_switch

SettingEntry.as_switch(**kwargs) -> Switch

Builds a ui.settings.Switch component bound to this entry — key, default, and icon (if set) are filled in automatically.

Parameters

  • **kwargs: Any other Switch constructor arguments (text, subtext, on_change, etc.).

Example

S.enable_autoupdates.as_switch(text="Show notifications")

zwylib.SettingsManager

class SettingsManager

Lower-level static access to plugin settings storage, used internally by SettingEntry and available directly if you’d rather not declare entries (e.g. for dynamic keys).

Methods

get

SettingsManager.get( plugin_id: str, item: Union[str, SettingEntry], default: Optional[_T] = None ) -> Optional[_T]

Reads a setting’s value for the given plugin.

Parameters

  • plugin_id (str): ID of the plugin the setting belongs to.
  • item (Union[str, SettingEntry]): Either a raw key string, or a SettingEntry (whose own default is used unless overridden).
  • default (Optional[_T], default None): Fallback value when item is a plain string key. Ignored if item is a SettingEntry.

Example

from zwylib import SettingsManager SettingsManager.get("MyPluginID", "greeting", "Hello!")

set

SettingsManager.set( plugin_id: str, item: Union[str, SettingEntry], value: Any, reload_settings=True ) -> None

Writes a setting’s value for the given plugin.

Parameters

  • plugin_id (str): ID of the plugin the setting belongs to.
  • item (Union[str, SettingEntry]): Either a raw key string, or a SettingEntry.
  • value (Any): The new value to store.
  • reload_settings (bool, default True): Whether to reload the plugin’s settings screen after writing.

Example

SettingsManager.set("MyPluginID", "greeting", "Hi!")

reload

SettingsManager.reload(plugin_id: str = None) -> None

Reloads a plugin’s settings from disk, refreshing its settings screen. Called automatically by set unless reload_settings=False.

Parameters

  • plugin_id (str, optional): ID of the plugin to reload. Inferred automatically from the call stack if omitted.

remove_setting

SettingsManager.remove_setting(key: str, plugin_id: str = None) -> None

Deletes a single setting key from storage entirely (as opposed to resetting it to a default).

Parameters

  • key (str): Key of the setting to remove.
  • plugin_id (str, optional): ID of the plugin the setting belongs to. Inferred automatically from the call stack if omitted.

Example

SettingsManager.remove_setting("legacy_flag")

Expandable Switches

For a group of related boolean settings — feature toggles, debloat options, and the like — ExpandableSwitchManager builds a single collapsible “select all” switch that expands into individual checkboxes for each option, without you having to manage the collapsed/expanded state yourself.

# ... metadata and zwylib import ... from zwylib import SettingEntry, ExpandableOption, ExpandableSwitchManager def on_feature_toggled(feature_id: int, enabled: bool): print(f"Feature {_features[feature_id]} {'enabled' if enabled else 'disabled'}!") _features = { 1: "Camera integration", 2: "Cloud sync", 3: "Background updates", } _options = [ ExpandableOption( text=label, settings_entry=SettingEntry(f"feature_{feature_id}_enabled", True), on_toggle=lambda enabled, feature_id=feature_id: on_feature_toggled(feature_id, enabled), ) for feature_id, label in _features.items() ] class MyPlugin(BasePlugin): def create_settings(self): return ExpandableSwitchManager.generate("Extra features", _options)

Each ExpandableOption’s on_toggle only ever receives the new bool state — the feature_id=feature_id default-argument trick above is what lets a single shared callback still know which switch triggered it.

zwylib.ExpandableOption

@dataclass class ExpandableOption: text: str settings_entry: SettingEntry on_toggle: Optional[(bool) -> None] = None

Describes one row inside an expandable switch group.

Fields

  • text (str): Label shown next to the checkbox.
  • settings_entry (SettingEntry): The setting this option reads from and writes to.
  • on_toggle (Optional[(bool) -> None], default None): Called with the new state whenever this option is toggled, either directly or via the group’s “select all” switch.

Methods

toggle

ExpandableOption.toggle() -> None

Flips this option’s current value and calls on_toggle, if set. This is what the checkbox’s own click handler calls internally — you generally won’t need to call it yourself.

zwylib.ExpandableSwitchManager

class ExpandableSwitchManager

Methods

generate

ExpandableSwitchManager.generate( main_switch_text: str, connected_options: List[ExpandableOption] ) -> List[Custom]

Builds (or retrieves, if already built) the collapsible switch group for main_switch_text and returns its current list of ui.settings.Custom entries — just splice the result straight into whatever create_settings returns. The group’s collapsed/expanded state and its “select all” checked state are tracked automatically, keyed by main_switch_text, for as long as the plugin stays loaded.

Parameters

  • main_switch_text (str): Label for the group’s top-level switch, and the key used to look up its state on subsequent calls — keep it stable across create_settings calls.
  • connected_options (List[ExpandableOption]): The individual toggles belonging to this group.

Example

class MyPlugin(BasePlugin): def create_settings(self): return ExpandableSwitchManager.generate("Extra features", _options)
Last updated on