DraftModeFramework

Reusable Flutter building blocks for shipping apps with a native look and feel without rebuilding the same page, section, row, dialog, navigation, and app-foundation patterns for every project.

The current focus is intentionally iOS-first. iOS is fully supported today; Android is planned, but not yet a first-class target. The primary goal of this repository today is to make it simple to assemble production-ready, Cupertino-flavoured apps from reusable primitives and a growing app-foundation toolkit.

Product Goal

This repository is meant to serve two connected roles today, while preparing for a broader app-foundation role over time:

  1. A reusable library in lib/ that currently focuses on UI, page, and navigation primitives and now also includes the first reusable forms, storage, and repository foundations.
  2. A runnable example/ host app that consumes that library and shows how to compose those primitives into real screens.

The guiding architectural principles are:

  • Keep layout, navigation scaffolding, and styling separate from business logic.
  • Prefer reusable primitives over screen-specific one-offs.
  • Keep the public API generic enough to be reused across apps.
  • Use the example app as a reference host and template, not as the source of product logic.

Source Structure

The public API stays available through stable root entrypoints in lib/, while the implementation is organized into ownership-focused domains:

  • lib/core/ for shared, non-visual foundations
  • lib/core/validation*.dart for shared validation contracts, contexts, and issue types used by forms, entities, and repositories
  • lib/ui/ for rendering-focused widgets and theme primitives
  • lib/page/ for page-level scaffolds
  • lib/navigation/ for navigation items and bars
  • lib/l10n/ for framework-owned localization resources and maintained localization implementation
  • lib/forms/ for form state, validation, formatters, and reusable form components
  • lib/entities/ for reusable field definitions and shared non-visual entity metadata
  • lib/storage/ for persistence contracts, adapters, and serialization
  • lib/repositories/ for typed entity-manager orchestration on top of storage

This keeps current imports stable while giving future modules clear landing zones.

Platform Status

  • iOS: fully supported and the current design baseline.
  • Android: planned, but still secondary until the iOS-first template and primitives feel production-ready.

For iOS-first apps, prefer staying close to Flutter's native Cupertino stack. The example app therefore uses CupertinoApp directly instead of an additional cross-platform wrapper so library integration stays transparent and predictable.

Library entrypoints

Import Contents Docs
package:draftmode_framework/components.dart All UI components (dialog, list, card, button, …) COMPONENTS.md
package:draftmode_framework/pages.dart Page scaffolds and navigation bars PAGES.md
package:draftmode_framework/theme.dart DraftModeUIThemeData + DraftModeUITheme THEME.md
package:draftmode_framework/formatter.dart Duration formatter FORMATTER.md
package:draftmode_framework/context.dart DraftModeUIContext.init for shared navigator/context wiring
package:draftmode_framework/buttons.dart Platform-aware icon tokens via DraftModeUIButtons
package:draftmode_framework/platform.dart DraftModeUIPlatform.isIOS helper
package:draftmode_framework/forms.dart Form state, validation-aware attributes, formatters, and reusable form widgets lib/forms/README.md
package:draftmode_framework/entities.dart Reusable field definitions, entity-aware schema fields, and schema validation helpers
package:draftmode_framework/storage.dart Storage contracts, adapters, JSON serializers, and typed storage entity managers lib/storage/README.md
package:draftmode_framework/repositories.dart Typed repository/entity-manager entrypoints for shared, secure, and HTTP-backed persistence lib/repositories/README.md
package:draftmode_framework/validation.dart Shared validation contracts and issue types for forms, entities, and repositories

Installation

Add the package to your pubspec.yaml as a path or git dependency and include Flutter's localization SDK:

dependencies:
  draftmode_framework:
    path: ../draftmode_framework
  flutter_localizations:
    sdk: flutter

Run flutter pub get after updating the file.

Localization Setup

DraftModeFramework bundles only framework-owned localizations: reusable UI defaults such as dialog action labels and countdown copy. Product, business, and app content must stay in the consuming application.

The localization layer is maintained source owned by this package. The ARB files in lib/l10n/ are the string inventory, while the Dart localization classes are intentionally checked in and reviewed like normal framework code.

Import package:draftmode_framework/localizations.dart and enable the bundled delegates in your host app:

return MaterialApp(
  localizationsDelegates: DraftModeLocalizations.localizationsDelegates,
  supportedLocales: DraftModeLocalizations.supportedLocales,
  home: const MyHomePage(),
);

The dialog falls back to Yes/No labels (and English countdown text) if the localization context is missing, which keeps integration tests and minimal host apps simple.

Global Context Wiring

Call DraftModeUIContext.init once during bootstrap to register either a navigatorKey or a root BuildContext. Afterwards you can invoke the dialog without supplying a context each time:

final navigatorKey = GlobalKey<NavigatorState>();

void main() {
  DraftModeUIContext.init(navigatorKey: navigatorKey);
  runApp(MyApp(navigatorKey: navigatorKey));
}

Future<void> _delete() async {
  final confirmed = await DraftModeUIDialog.show(
    title: 'Delete file?',
    message: 'This cannot be undone.',
  );
  if (confirmed == true) {
    // Proceed with deletion.
  }
}

When neither argument is passed to DraftModeUIDialog.show nor registered via DraftModeUIContext.init the helper throws a StateError to highlight the missing context.

Example App

The /example directory is the reference host app for this package. It wires DraftModePage, DraftModeUISection, DraftModeUIRow, lists, cards, buttons, menus, forms, and storage-backed feature flows together so the library can be evaluated as a coherent app shell instead of isolated widgets.

Use it as both a visual component library and a starting point for the app structure this repository is trying to standardise:

make example-launch-simulator
make example-run

# or manually
cd example
flutter run

Because DraftModeFramework is a library, the actual concrete app realization lives in example/. That is intentional: the library defines reusable primitives, while the example shows how they behave in real screens and provides visual feedback during development.

The profile feature also exercises the real storage adapters. It now combines backend switching, pull-to-refresh, swipe-to-delete list behavior, and a typed form workflow on top of the real DraftMode storage/entity-manager stack. Shared and secure storage use their package implementations directly, while the HTTP path uses the real HTTP storage adapter against an injected in-memory http.BaseClient. That keeps the example close to production wiring without requiring Docker or an external service during local UI work.

When a feature schema is available, the typed storage entity managers can reuse that same schema to validate decoded entities on load and outgoing entities on save. This keeps form-time and persistence-time validation aligned.

When schemas express date/time relationships, prefer vAfter(...) or vAfterOrEqual(...) instead of the generic numeric vGreaterThan(...) so the rule reads like the actual domain constraint.

Within example features, prefer a three-part split when forms describe a domain object:

  • entities/ for the plain data object
  • schemas/ for shared field definitions, defaults, labels, and validators
  • bindings/ for mapping between DraftModeFormState and the entity

For clonable consumer apps, use the separate draftmode/ci.cd/templates/flutter repository instead of copying example/ directly. Changes to bootstrap rules, recommended folder structure, and LLM guidance should be reviewed for both repositories together. example/ stays framework-owned and may continue to include showcase or validation-specific flows that should not become product defaults.

Assets

The assets/images/logo.png asset is exported for downstream packages. When referencing it directly, include the package argument so Flutter looks inside the dependency bundle:

Image.asset('assets/images/logo.png', package: 'draftmode_framework');

Testing

Run flutter test --coverage to execute the test suite and verify the framework keeps a high coverage bar across UI, forms, storage, entity-manager/repository, and foundation modules.

Contributing

  1. Update the framework-owned localization resources in lib/l10n/ when introducing reusable package-level UI strings, while keeping lib/localizations.dart as the stable public facade.
  2. Run flutter test --coverage.
  3. Submit PRs with a concise summary of behavior changes and test results.

Publish pub.dev

via Gitlab

  1. Login locally to dart dart pub login
  2. Once logged in, locate your credentials file
  • Windows: %APPDATA%\Dart\pub-credentials.json
  • Linux/macOS: ~/.config/dart/pub-credentials.json
  • macOS with homebrew: ~/Library/Application Support/dart
  1. Copy the contents of this file
  2. Add Credentials to GitLab
  • Goto to your project/group
  • Navigate to Settings > CI/CD and expand Variables
  • Click Add Variable (Key: PUB_CREDENTIALS, Value: content of file, Optional: Masked and Protected)

Release

  • Version: 1.0.1
  • Image: not-configured:1.0.1
  • Changelog: see CHANGELOG.md

This section is managed by CI.

Libraries

buttons
Platform-aware button icon tokens for DraftMode components.
components
Rendering-focused reusable UI components for DraftModeFramework apps.
context
Global DraftMode context registration helpers.
core/context
core/formatter/date_time
core/platform
core/validation
core/validation_context
core/validation_issue
entities
Shared field definitions and schema helpers for typed entities.
entities/entity_field
entities/entity_schema
entities/field_definition
formatter
Shared formatting helpers that are not specific to forms.
forms
Form state, validation-aware attributes, and reusable form widgets.
forms/_error_text
forms/attribute
forms/button
forms/button_text
forms/calendar
forms/context
forms/date_time
forms/field
forms/form
forms/formatter
forms/formatter/double
forms/formatter/double_signed
forms/formatter/int
forms/formatter/int_signed
forms/formatter/number
forms/list
forms/segmented_control
forms/switch
l10n/app_localizations
l10n/app_localizations_de
l10n/app_localizations_en
localizations
DraftModeFramework localization delegates and supported locales.
navigation/bottom
navigation/item
navigation/item_bottom
navigation/item_screen
navigation/item_top
navigation/top
page/page
page/ui_page
pages
Page scaffolds and navigation primitives for DraftModeFramework apps.
platform
Platform helpers used by DraftMode widgets and apps.
repositories
Typed repository and entity-manager adapters built on DraftMode storage.
repositories/storage_entity
repositories/storage_entity_http
repositories/storage_entity_manager
repositories/storage_entity_secure
repositories/storage_entity_shared
storage
Storage adapters, serializers, and typed storage-backed entity managers.
storage/http_storage
storage/secure_storage
storage/serializer
storage/shared_storage
storage/storage
theme
DraftMode theme tokens and theme access helpers.
ui/buttons
ui/components/badge
ui/components/button
ui/components/button_presets
ui/components/calendar
ui/components/card
ui/components/date_time
ui/components/date_time_style
ui/components/date_timeline
ui/components/dialog
ui/components/list
ui/components/list_dismissible
ui/components/list_text
ui/components/row
ui/components/section
ui/components/segmented_control
ui/components/spinner
ui/components/switch
ui/components/timeline
ui/components/toast
ui/theme
validation
Shared validation contracts used by forms, entities, and repositories.