Edadat - إعدادات
flutter_settings_framework
Declarative settings for Flutter — bilingual search, Riverpod wiring,
and ready-made tiles / registry pages.
Live demo
— open the example catalog in the browser
zyzto.github.io/Edadat
Live demo · Install · Quick start · Screenshots · Features · Types · Example · Changelog · Versioning · العربية · Arabic UI style
The name edadat comes from Arabic إعدادات (iʿdādāt): settings / configurations — plural of إعداد (iʿdād).
Why
Most Flutter apps grow a pile of preference notifiers, keys, and one-off tiles. Then you need:
- declarative definitions instead of per-setting boilerplate
- search that works in more than the current UI language
- a consistent settings page without rebuilding every screen
Edadat covers that path with a stream/callback core, a shipped Riverpod adapter + UI, and bilingual search indexing. Other state-management adapters are not included today (flutter_riverpod is a hard dependency).
On pub.dev: flutter_settings_framework · Repo: Zyzto/Edadat
Screenshots
English catalog · Arabic RTL · Bilingual search — try them in the live demo
Rendered from the example/ catalog (flutter test test/screenshots_test.dart).
Features at a glance
| Area | What you get |
|---|---|
| Definitions | Typed settings (Bool, Enum, Color, …) in a few lines |
| Search | Multi-language index via PreIndexedLocalizationProvider + synonyms |
| Riverpod | initializeSettings, SettingsProviders, ref.watchSetting / updateSetting |
| UI | Tiles, sections, persistent/compact search, RegistrySettingsPage |
| Jump-to | SettingAnchorRegistry scroll + highlight after search |
| Storage | SharedPreferencesStorage, or your own SettingsStorage |
| Actions | Non-persisted ActionSetting rows that stay searchable |
Core: stream/callback controller (no Riverpod import). Shipped integration: Riverpod adapter + Riverpod-based settings UI.
Install
dependencies:
flutter_settings_framework: ^0.9.0
Or:
flutter pub add flutter_settings_framework
Git tag pin (see VERSIONING.md):
dependencies:
flutter_settings_framework:
git:
url: https://github.com/Zyzto/edadat.git
ref: v0.9.0
import 'package:flutter_settings_framework/flutter_settings_framework.dart';
Current version: 0.9.0.
Optional Safaeh chrome
Safaeh is included as a dependency, but no Safaeh widget is mounted by the default settings UI. Import the separate entrypoint when the host wants Safaeh's page-index, search, or adaptive modal chrome:
import 'package:flutter_settings_framework/safaeh.dart';
SafaehSettingsPageIndexOverlay(
title: 'On this page',
sections: registry.getSortedSections(),
sectionKeys: sectionKeys,
labelBuilder: (section) => translate(section.titleKey),
activeId: activeSectionId,
onSelect: jumpToSection,
);
The normal flutter_settings_framework.dart entrypoint remains unchanged;
search indexing and result ranking continue to come from Edadat's
SearchIndex. The same entrypoint also exposes the animated search UI:
SafaehSettingsSearchButton(
isOpen: searchOpen,
onPressed: toggleSearch,
),
Stack(
fit: StackFit.expand,
children: [
const SettingsBody(),
SafaehSettingsSearchOverlay(
isOpen: searchOpen,
onClose: closeSearch,
searchIndex: searchIndex,
onResultSelected: jumpToSetting,
sectionTitleBuilder: sectionTitle,
settingTitleBuilder: settingTitle,
),
],
)
The overlay uses Safaeh's glass appearance, keeps close and clear actions separate, groups results by section without repeated breadcrumbs, and leaves navigation and setting permissions to the host app.
The same entrypoint re-exports Safaeh ^0.5.0: adaptive sheets, list/status
chrome (SafaehEmptyState, SafaehSectionHeader, SafaehGlyphAvatar,
SafaehLtrText, …), info/action sheets, and applySafaehMaterialChrome.
Sheets render as a bottom sheet on phones and a centered dialog on wider
layouts:
return SafaehTheme(
data: const SafaehThemeData(
floatingAppearance: SafaehFloatingAppearance(
style: SafaehFloatingSurfaceStyle.glass,
),
),
child: MaterialApp(...),
);
final choice = await showSafaehTilePicker<String>(
context: context,
title: 'Theme',
selected: currentTheme,
options: const [
SafaehTileOption(value: 'light', label: 'Light'),
SafaehTileOption(value: 'dark', label: 'Dark'),
],
);
Quick start
1. Define settings
import 'package:flutter/material.dart';
import 'package:flutter_settings_framework/flutter_settings_framework.dart';
const generalSection = SettingSection(
key: 'general',
titleKey: 'general',
icon: Icons.settings,
order: 0,
);
const themeModeSetting = EnumSetting(
'theme_mode',
defaultValue: 'system',
titleKey: 'theme',
options: ['system', 'light', 'dark'],
section: 'general',
searchTerms: {
'en': ['theme', 'dark', 'light', 'mode'],
'ar': ['المظهر', 'داكن', 'فاتح'],
},
);
const notificationsSetting = BoolSetting(
'notifications_enabled',
defaultValue: true,
titleKey: 'notifications',
icon: Icons.notifications,
section: 'general',
);
SettingsRegistry createMyRegistry() {
return SettingsRegistry.withSettings(
sections: [generalSection],
settings: [themeModeSetting, notificationsSetting],
);
}
2. Initialize (override all three providers)
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final en = Map<String, String>.from(
jsonDecode(await rootBundle.loadString('assets/translations/en.json')) as Map,
);
final ar = Map<String, String>.from(
jsonDecode(await rootBundle.loadString('assets/translations/ar.json')) as Map,
);
final settings = await initializeSettings(
registry: createMyRegistry(),
storage: SharedPreferencesStorage(),
localizationProvider: PreIndexedLocalizationProvider({
'en': en,
'ar': ar,
}),
);
runApp(
ProviderScope(
overrides: [
settingsControllerProvider.overrideWithValue(settings.controller),
settingsSearchIndexProvider.overrideWithValue(settings.searchIndex),
settingsProvidersProvider.overrideWithValue(settings),
],
child: const MyApp(),
),
);
}
3. Use in widgets
class MyWidget extends ConsumerWidget {
const MyWidget({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final enabled = ref.watchSetting(notificationsSetting);
return SwitchSettingsTile.fromSetting(
setting: notificationsSetting,
title: 'notifications'.tr(),
value: enabled,
onChanged: (value) => ref.updateSetting(notificationsSetting, value),
);
}
}
4. Registry page
RegistrySettingsPage(
registry: myRegistry,
settings: ref.settings,
title: 'settings'.tr(),
searchHint: 'search_settings'.tr(),
sectionTitleBuilder: (key) => key.tr(),
enumLabelBuilder: (key) => key.tr(),
)
Search results: ref.watch(settingsSearchResultsProvider(query)).
Setting types
| Type | Class | Example |
|---|---|---|
| String | StringSetting |
User names, paths |
| Boolean | BoolSetting |
Toggle features |
| Integer | IntSetting |
Counts, days |
| Double | DoubleSetting |
Scales, spacing |
| Color | ColorSetting |
Theme colors |
| Enum | EnumSetting |
Limited options |
| String List | StringListSetting |
Tags, filters |
| Action | ActionSetting |
Export, about (non-persisted) |
Multi-language search
Pass PreIndexedLocalizationProvider at initializeSettings so titles, subtitles, and section titles are indexed for every locale. Add searchTerms for synonyms.
For Arabic UI wording (MSA tone, anti-calque habits, and a shared glossary), see Arabic UI localization style guide.
const languageSetting = EnumSetting(
'language',
defaultValue: 'en',
titleKey: 'language',
options: ['en', 'ar'],
searchTerms: {
'en': ['locale', 'english', 'arabic'],
'ar': ['لغة', 'إنجليزي', 'عربي'],
},
);
final results = searchIndex.search('عربي');
Set visible: false on internal settings so they never appear in search (order alone does not hide them from SearchIndex).
UI inventory
Tiles: SettingsTile, SwitchSettingsTile, SelectSettingsTile, SliderSettingsTile, ColorSettingsTile, NavigationSettingsTile, ActionSettingsTile, InfoSettingsTile
Layout: SettingsSectionWidget, SettingsSearchBar (persistent / compact), SettingAnchorRegistry / scrollToSetting, SplitScreenLayout, RegistrySettingsPage, CardSettingsSection
Helpers: ref.settings, ref.watchSetting / updateSetting / resetSetting, settingsSearchResultsProvider, buildSearchResultWidgets, isSettingEnabled
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your App (Widgets) │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ Riverpod adapter + settings UI │
│ • SettingNotifier<T> / SettingsProviders │
│ • RegistrySettingsPage, tiles (Riverpod-coupled) │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ Core (streams / callbacks, no Riverpod) │
│ • SettingsController · SettingsRegistry · SearchIndex │
│ • SettingsStorage abstraction │
└─────────────────────────────┬───────────────────────────────┘
│
┌─────────────────────────────▼───────────────────────────────┐
│ SharedPreferencesStorage · MemoryStorage · custom │
└─────────────────────────────────────────────────────────────┘
Example
Live demo — zyzto.github.io/Edadat
The hosted catalog is the example/ web build. CI deploys it after tests pass
on main.
See example/ for a bilingual RegistrySettingsPage catalog: Bool, Enum, Color, Double, Int, String, StringList, Action, dependsOn, Safaeh's “On this page” index, and the new glass search overlay. Language and theme toggles sit above the catalog (same chrome as Safaeh).
The example is package-style (web only in-tree); analyze with:
cd example && flutter pub get && dart analyze --fatal-infos && flutter test
example/test/screenshots_test.dart writes catalog PNGs to screenshots/.
To run on a device, generate the other platforms (flutter create . --platforms=android,ios inside example/). Details: example/README.md.
Package tests:
dart analyze --fatal-infos && flutter test
Branding
The logo wordmark uses Baz (Baz Light) — the same Arabic typeface as Siglat. The face is vendored at assets/fonts/baz-Light.otf; the SVG outlines the glyphs so GitHub/pub.dev render without loading the font.
Versioning
See VERSIONING.md and CHANGELOG.md. Tags are vX.Y.Z and must match pubspec.yaml.
License
MPL-2.0 — weak copyleft, commercial use allowed. Modified package files stay under MPL; your app can remain closed-source.
Libraries
- flutter_settings_framework
- Declarative settings for Flutter with bilingual search and a Riverpod adapter plus ready-made settings UI.
- safaeh
- Opt-in Safaeh presentation helpers for the settings framework.