draftmode_framework 1.0.1
draftmode_framework: ^1.0.1 copied to clipboard
Reusable Flutter package for iOS-first native-feeling app foundations.
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:
- 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. - 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 foundationslib/core/validation*.dartfor shared validation contracts, contexts, and issue types used by forms, entities, and repositorieslib/ui/for rendering-focused widgets and theme primitiveslib/page/for page-level scaffoldslib/navigation/for navigation items and barslib/l10n/for framework-owned localization resources and maintained localization implementationlib/forms/for form state, validation, formatters, and reusable form componentslib/entities/for reusable field definitions and shared non-visual entity metadatalib/storage/for persistence contracts, adapters, and serializationlib/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 objectschemas/for shared field definitions, defaults, labels, and validatorsbindings/for mapping betweenDraftModeFormStateand 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 #
- Update the framework-owned localization resources in
lib/l10n/when introducing reusable package-level UI strings, while keepinglib/localizations.dartas the stable public facade. - Run
flutter test --coverage. - Submit PRs with a concise summary of behavior changes and test results.
Publish pub.dev #
via Gitlab #
- Login locally to dart
dart pub login - 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
- Copy the contents of this file
- 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.