moarch 5.0.0
moarch: ^5.0.0 copied to clipboard
Flutter CLI — scaffold Clean Architecture projects with Riverpod or flutter_bloc, FVM and your own conventions.
Changelog #
All notable changes to this package are documented in this file, newest first.
5.0.0 #
Breaking for both stacks. A project generated with 5.0.0 does not look like
one generated with 4.x. Nothing migrates an existing project: moarch update
refreshes a file where the current templates put it, so a 4.x bloc project
keeps its presentation/states/ folder — and update stops refreshing what is
in it — until the files are moved by hand. A 4.x Riverpod project keeps its
providers and is not touched.
Riverpod uses get_it for dependency injection #
Riverpod declared a provider beside every class it built. It no longer does.
lib/config/di/injector.dart — the file the bloc stack has had since 4.0.0 —
is now generated for both stacks, and holds the same things in both:
clients, services, datasources, repositories and use cases.
- Gone from a Riverpod project:
dioClientProvider,secureStorageProvider,tokenStorageProvider,firebaseAuthProvider,firebaseDbProvider,permissionProvider,mediaServiceProvider,urlLauncherProvider,notificationServiceProvider,firebaseNotificationsServiceProvider,biometricServiceProvider,connectivityProvider,debouncerProvider,dialogProvider,modalProvider, and the per-feature<x>RemoteDataSourceProvider/<x>LocalDataSourceProvider/<x>RepositoryProvider/get<X>Provider. Each is agetIt<Thing>()now. - Riverpod holds the state; get_it holds everything the state is built
from. What stays a provider is what actually holds state: the feature
notifiers,
authNotifierProvider,languageProvider,routerProvider,hasInternetProviderandmaintenanceStatusProvider— and those read their dependencies out of the locator. - A notifier is the seam between the two.
AsyncNotifierneeds theRefonly Riverpod can hand it, so it is not registered in get_it; it declaresOrdersRepository get _repo => getIt<OrdersRepository>();in place ofref.watch(ordersRepositoryProvider). moarch create featurenow registers what it generated in a Riverpod project too — the datasource, the repository and the use case, at the// moarch:registrationsanchor. The notifier is the only thing it leaves out, because there is nothing to register.main.dartcallsawait setupInjector()beforerunAppin both stacks. TheProviderContainer/UncontrolledProviderScopedance a Riverpod project needed when a service held aRefis gone with the services: it is a plainProviderScopeagain, whatever is selected.get_itis a dependency of both stacks.moarch doctorchecks for it and for the locator in both.- The services that only differed in how they were reached — secure storage,
biometrics, permissions, media, URL launcher, notifications, FCM, debouncer,
dialogs, modals,
AppButton— now have one body instead of two.config/firebase/firebase_providers.dartandcore/network/dio_client.dartare the same file in both stacks and moved out of the per-stackAppTemplates.
A bloc's state lives with its bloc #
presentation/states/<x>_state.dart moves to presentation/blocs/<x>_state.dart
on the bloc stack, beside the events and the bloc. The three are one unit — the
handlers emit the states — and a change to any of them is usually a change to
all three. Riverpod is unchanged: presentation/states/ beside
presentation/notifiers/.
Bloc views are BlocConsumer #
The generated view is a BlocConsumer rather than a BlocBuilder, with a
listener prepared for the states the feature has and
listenWhen: (previous, current) => previous != current. It is the bloc answer
to ref.listen: listener runs once per new state — where a toast, a dialog
or a context.push belongs — while builder runs on every rebuild.
Fixes #
moarch create blocwrote Riverpod'score/utils/action_notifier.dartinto a bloc project, importingflutter_riverpodin a project that does not have it. It also named a mixin (ActionBlocMixin) that has never existed. The file is no longer written.- The Riverpod feature notifier declared a repository getter it never called,
which the analyzer reports as an unused element, and imported the use case
without using it. It now calls its dependency in
build()and takes the use case when there is one — the same rule the bloc has followed since 4.0.0 (the repository regardless on the Firestore variant, whose live query no use case wraps). - The Riverpod repository implementation imported
app_exception.dartwithout using it, and the local datasource imported its model without using it.
4.0.0 #
Riverpod projects are unaffected by this release — every template, field and file path on that side is unchanged. Everything below is the new stack.
Features #
- flutter_bloc is a supported stack.
moarch initnow asks which state management the project uses before anything else — Riverpod, as before, or flutter_bloc withget_itfor dependency injection. Every state-bearing template exists in both, underlib/src/templates/riverpod/andlib/src/templates/bloc/: the feature scaffold, both auth features,AppAsyncView, the action listener, the maintenance gate, the router, the Dio client andmain.dart. Same layers, same file names, same layer boundaries — a project reads the same way whichever it took. - A bloc feature is sealed on both sides: a
<Feature>Eventfamily, and a<Feature>Statefamily ofInitial/Loading/Success/Failure, so the view is aswitchthe compiler checks for completeness. The family is the status — there is no flag or enum on top of it. States and events extendEquatable, which is load-bearing: bloc drops an emit equal to the current state andBlocBuilderrebuilds on the same test, so without it every emit repaints. AuthStatefollows the same shape:AuthInitial(restoring, which is what parks the router on splash),AuthLoading,AuthAuthenticated,AuthUnauthenticated,AuthFailure.- Bloc views are plain flutter_bloc:
BlocProviderin aPage,BlocBuilderand aswitchin theView.AppAsyncView,ref.listenActionand any shared action base are not generated into a bloc project — they exist to map Riverpod's opaqueAsyncValueonto four screens, and a sealed family needs no wrapper.moarch create widget async-viewsays so rather than writing a file that cannot compile. moarch create featurereads the stack offpubspec.yamland generates for it — no new flag. In a bloc project it also registers what it generated inlib/config/di/injector.dart, at the// moarch:registrationsanchor.moarch create bloc <feature> <name>adds a state + event + bloc trio to a feature that already exists, wired to that feature's repository.moarch init --state riverpod|blocpicks the stack without the checklist, so--allcan reach either one.- Generated bloc projects get
bloc_lintin dev dependencies, the recommended ruleset inanalysis_options.yaml, and abloc lintstep in the CI workflow. A freshly scaffolded project passes it with no findings. moarch doctorchecks what the project's own stack needs:get_itand a locator with its anchor comment for bloc,flutter_riverpodotherwise.
Changes #
main.dart,action_notifier.dart,app_router.dart,dio_client.dart,firebase_providers.dartandlanguage_service.dartmoved out ofCoreTemplates/ConfigTemplates/ServicesTemplatesinto the per-stackAppTemplates. Nothing changes in what a Riverpod project generates.- Templates that differ only in how a service is reached — the services, secure
storage, the biometric service,
AppButton, the dialog and modal helpers, the design-system preview — take the stack as a parameter instead of being duplicated, so there is one body to maintain.
3.2.2 #
Fixes #
moarch create widgetrecorded only the files it wrote this run, so a widget already on disk stayed out of.moarch.yaml— andmoarch updatethen read it as a file it could not vouch for.create widget <name>andcreate widget allnow also record a widget they skipped when its content is still exactly what the current templates generate, whether it got there from an earlier run, a copy, or a run that stopped before saving. A file that differs is still left out: that content is yours.
3.2.1 #
Features #
AppBottomNavtakes two more looks apart from itsstyle.labels(auto/below/none) says where the destination names are written, so the pill can stack over its label instead of opening sideways, the dot can carry one at all, and any style can drop to icons only — a label that is not drawn still reaches a screen reader and still names its icon on a long press.floatingShape(full/rounded/square) cuts the floating card's corner, andpillShapethe corner of the fill behind the selection — which Material's own bar reads too, as its indicator. Both take aBorderRadiusof the project's own (floatingBorderRadius,pillBorderRadius) where the three names are not the number wanted.AppAdaptiveNavpasses all four down asbottomNavLabels,bottomNavShape,bottomNavPillShapeand their radius pair. Defaults are what the bar drew before.- The dark theme is now a choice.
initasks for it (Dark theme, off by default): with it off,AppConstantsdeclares one brand palette andAppThemeonelightgetter — around 290 fewer lines in the files you actually edit. With it on, every color token gains its*Darkcounterpart,AppTheme.darkis generated, andmain.dartgetsdarkTheme+themeMode: ThemeMode.system. moarch create theme --darkadds the dark half to a project scaffolded without it, and--no-darktakes it away again. The palette, the theme,main.dart,AppToastand the design-system preview are generated against each other, so the switch is all of them at once: files moarch wrote and nobody edited are rewritten silently, and an edited one stops the run with a diff instead (--diff,--dry-run,--force,--yes).- The scope is read off
app_theme.dartrather than remembered, somoarch updateandmoarch create widgetfollow what the project actually is — including after switching.
Fixes #
main.dartshippeddarkTheme: AppTheme.darkcommented out, so a generated app was light-only whatever the palette said. The design-system preview had the same line commented out under a working brightness toggle, leaving a button that did nothing. Both are now wired when the project takes dark.
Changes #
AppConstantsdrops the tokens nothing in the kit read:accentActive,accentRestorative,accentEnergetic(the tab indicator usesprimary),padding8,paddingH16,paddingH24,paddingV16,borderRadius24andduration100. The remaining colors are grouped brand → surfaces → status, with the dark palette (when present) in one block rather than three.
Upgrading #
An existing project keeps its dark theme — the scope is read off
app_theme.dart, so moarch update sees what is already there. Two things to
look at in the diff it offers:
moarch update constantsremoves the tokens listed above. If your own code reads one of them, keep it: it is your palette now.moarch update mainuncommentsdarkThemeand setsthemeMode, which is what the dark palette was always for — but it does mean the app starts following the system brightness.moarch create theme --no-darkis the way out if it was never meant to.
3.1.8 #
3.1.4 #
Fixes #
-
The design-system preview renders in the app's real theme. It built its own
ThemeData(useMaterial3: true)behind aTODO, so the one screen whose job is showing what the kit looks like was the one screen not showing it — every widget previewed in stock Material colors and type instead of the project's. It now usesAppTheme.light/AppTheme.dark, the same themesmain.dartmounts, so editinglib/config/theme/app_theme.dartmoves the preview with it.app_theme.dartis written unconditionally byinit, so the new import needs nothing the scaffold did not already have. -
initanddoctornow surface thefvm usestep.initwrites a.vscode/settings.jsonpointingdart.flutterSdkPathat.fvm/flutter_sdk, but onlyfvm usecreates that symlink and.fvm/is gitignored — so on a fresh scaffold or a fresh clone the path did not exist. Nothing reports that: the Dart extension silently falls back to the first Flutter onPATH, and debug, hot reload and the analyzer all run the SDK the.fvmrcpin exists to avoid. The only symptom is analyzer output that disagrees withfvm flutter analyze.initnow printsfvm useas the first step, ahead ofpub get, andmoarch doctorgrew a check for it:-
dart.flutterSdkPathpointing at a path that does not exist — error, with thefvm usefix. -
the symlink present but dangling, the pinned SDK not installed — error, pointing at
fvm install. -
a versioned
.fvm/versions/<version>path, which is whatfvm userewrites the setting to and which stops following.fvmrc— warning, anddoctor --fixpoints it back at.fvm/flutter_sdk. -
settings.jsonmissing, or carrying nodart.flutterSdkPath— warning.An absolute path is left alone as a deliberate override, and a project with no `.fvmrc` gets none of these findings.
-
-
The README documents that the generated
.fvmrcpins thestablealias rather than a version, sofvm installon CI or a teammate's machine can resolve to a different SDK than your cache holds, and how to pin for real once the project ships.
3.1.2 #
Features #
-
MaintenanceGate— a kill switch the backend owns. While a flag says maintenance, it replaces the whole app with a screen carrying the title and message the backend sent, so the team taking the API down can empty the app, and reword the notice, without a release. Mounted inMaterialApp.builderso it wraps the Navigator: above every route the router can reach, including anything pushed after the flag flips. It replaces rather than covers, so nothing is left to tap and the back button has nothing to pop. It fails open — loading, offline, endpoint down or rules denied all read as "up", because a fault in the check must not lock out every user at once. The provider follows the project's backend: a live Firestoresnapshots()listener, a polled Dio endpoint (five minutes, plus on resume), or a stub to point at your own source. Available in theinitchecklist and asmoarch create widget maintenance-gate. -
Widgets whose source varies with the project are now resolved in one place,
WidgetCatalog.sourceFor, instead of being special-cased separately ininit,create widgetandupdate— three copies that had to agree, orupdatewould report a file as edited the moment it was generated. -
initwritesandroid/app/proguard-rules.pro— the keep rules that were until now only printed indocs/SECURITY_BEFORE_DEPLOYMENT.mdfor you to copy across: the Flutter engine, Play Core, Firebase, OkHttp, coroutines, enums, native methods, andSourceFile,LineNumberTableso a release stack trace still de-obfuscates. The file is inert until the release build type turns R8 on, so enabling minification before a release is now just that gradle block rather than that block plus a round of release-only crashes. The doc renders the same template, so the two cannot drift. Refreshable withmoarch update proguard(newandroidgroup).
Docs #
CHECKLIST_BEFORE_DEPLOYMENT.mdandSECURITY_BEFORE_DEPLOYMENT.mdreconciled with what the scaffold actually does. Both were generic checklists that asked you to do workinithad already done. Items the scaffold handles now arrive ticked and name the file that handles them (config/env/app_env.dart,TokenStorage,ValidationService,app_logger.dart, the CI jobs), so the OWASP mapping stays complete but you can see at a glance what is left. Everything unticked is genuinely yours.- Gaps the checklists implied were covered are now called out as gaps, with the
exact steps: no
.env.example, nonetwork_security_config.xml, R8 rules written but not enabled,build/debug-info/never uploaded by the Android workflow, andbuild_ipa.ymlarchiving throughxcodebuildwithout carrying the Dart obfuscation flags. - Corrected content that no longer matched the generator: the
enviedexample pointed atlib/core/env/env.dartand classEnv(the scaffold generateslib/config/env/app_env.dartandAppEnv), the R8 block was Groovybuild.gradlewhere the scaffold patchesbuild.gradle.kts, and two code examples had Portuguese UI strings in an otherwise English doc.
3.1.0 #
Features #
moarch create flavors— sets a project up fordev/staging/prodflavors (or the names you pass) through flutter_flavorizr, configured so the project keeps onemain.dart— yours, untouched. It writes aflavorizr.yamlwhoseinstructionsrun only the native-side processors (android:flavorizrGradle,android:buildGradle,android:androidManifest,ios:xcconfig,ios:plist) plusflutter:flavors, and adds the dev dependency — sodart run flutter_flavorizrpatches the native side and generateslib/flavors.dart, and nothing else. No per-flavormain_<flavor>.dartentry points. The Android application id and iOS bundle id are read from the project, non-production flavors get suffixed ids so the builds install side by side, and the flavored entriesinitalready writes into.vscode/launch.jsonstart working.moarch create model --from-json <file>— hands the command a sample of the payload the API actually returns, and the entity and model come out with real fields instead of TODOs: a completefromJson/toJsonkeyed on the original JSON keys,fromEntity/toEntity, and==/hashCode. ISO-dated strings becomeDateTime, doubles parse throughnumso an int in the payload doesn't crash them, homogeneous lists keep their element type, snake_case keys become camelCase fields, and a top-level JSON list is sampled at its first element. Anullin the sample can only type asdynamic, and is called out so you can tighten it by hand.
Fixes #
- The
.vscode/launch.jsontemplate carried a trailing comma that strict JSONC parsers flag, introduced in 3.0.0 — removed, and the template tests brought back in line with the 3.0.0 template rewrite. moarch init --dry-runlisted every file, including ones a real run would have skipped because they already exist. The preview now makes the same decision against the same disk as a real run.- A failed scaffold's rollback removed the files it created but left their empty directory chains behind — the directories are now removed too (only ever ones the run itself created, and only when empty).
moarch updatefailing partway through a refresh left the project half on the old templates and half on the new. The files already refreshed are now restored to what they held before.
Meta #
- The changelog accumulates again. Each release used to replace the whole file, so pub.dev only ever showed the latest entry — the full release history below was restored from git.
topicsandissue_trackeradded topubspec.yaml.- CI now verifies
lib/src/version.dartmatchespubspec.yaml. example/example.dartrewritten to match the current CLI.
2.9.0 #
Features #
- Firebase Auth is now a backend choice, not just a provider. Selecting it with
the auth feature generates that feature against Firebase instead of REST:
email/password, Google sign-in, password reset, account deletion, and a
session restored from
authStateChanges(). Same layers and provider names, no token storage, and Dio is no longer pulled in for it. moarch create featurefollows the project's backend: in a Firestore project the datasource holds_firestoreinstead of_dio, withfetchAll/fetchOne/watchAll/create/save/deleteover one collection and aStringdocument id. With both backends installed, the layer checklist asks which one the feature talks to.AppExceptionmaps the Firebase failures an app actually hits: afromFirebaseAuthErrorfactory for the auth codes (invalid-credential,email-already-in-use,weak-password,requires-recent-login,too-many-requests…) and the Firestore codes (permission-denied,unavailable…) infromFirebaseError. Newauthandcancelledtypes, plusAppException.cancelled()for a dismissed sign-in sheet.- New
core/network/safe_firebase_call.dart— the Firebase counterpart ofsafeApiCall, for one-off calls and for streams. - New
docs/FIREBASE_SETUP.mdcovering the work that lives outside Dart:flutterfire configure, enabling the sign-in providers, the Android SHA-1/SHA-256 fingerprints, the iOSGIDClientIDandREVERSED_CLIENT_IDURL scheme, the web client id, and a starting set of Firestore rules. initwrites the two iOS Google sign-in keys intoInfo.plist, taking the real values fromGoogleService-Info.plistwhen it is already there and leaving documented placeholders when it isn't. Existing URL types are kept.
Fixes #
main.dartnow callsFirebase.initializeApp()for Firestore and Firebase Auth, not only for Crashlytics — a project with either selected used to throw "No Firebase App '[DEFAULT]' has been created" on its first provider read.
Doctor #
- New checks for a half-wired Firebase project: missing
firebase_coreorgoogle_sign_in, noFirebase.initializeApp()inmain.dart, a missinggoogle-services.json/GoogleService-Info.plist, andInfo.pliststill carrying the placeholder Google client ids — which--fixfills in fromGoogleService-Info.plist.
2.8.0 #
Features #
moarch updatenow refreshes everything the CLI generates, not just the widget kit. The gap it closed for widgets was the same gapcore/,config/, the auth feature, the docs and the workflows had all along: a project scaffolded two versions ago still carries the oldvalidation_service.dart, and nothing told you which improvements you were missing or which changes were your own.- Every file is addressable on its own —
moarch update validation,moarch update extensions,moarch update theme,moarch update logger. With no arguments the whole project is considered, exactly as before. - Or by group, when a whole area has drifted:
widgets,core,network,security,services,config,auth,docs,workflows,project,ios. They combine freely —moarch update security docs extensions. moarch update --listprints every name and group with the file it maps to, so the slugs don't have to be guessed.- Templates that vary are rebuilt against the project they land in, not
against a default:
app_logger.dartkeeps its Crashlytics branch,main.dartkeeps the router, localization and notification services the project actually has,app_exception.dartkeeps its Dio and Firebase mappings, andbuild_ipa.ymlkeeps its Firebase steps. The options are read back off the generated files andpubspec.yaml— the record that stays true as the project is edited. - It refreshes, it never scaffolds. A file the project declined at
initis not missing, so naming it does nothing rather than generating it.moarch update biometricin a project without biometrics is a no-op. - The three buckets are unchanged, and now apply to all of it: untouched
files refresh silently, edited ones are listed and diffed and never
written without
--force.
- Every file is addressable on its own —
Improvements #
moarch initnow records every file it writes in.moarch.yaml, where it previously recorded only the widgets. That record is the whole basis for telling an untouched generated file from one you edited — without it the rest of the scaffold could only ever be reported as needs review.- A project scaffolded before 2.8.0 has no record of its non-widget files,
so the first
moarch updatelists them as needing review even where they are untouched. Refreshing or confirming them re-records them, and subsequent runs are exact. That is the safe direction: nothing is overwritten on the strength of a guess.
- A project scaffolded before 2.8.0 has no record of its non-widget files,
so the first
.fvmrcandflutter_native_splash.yamlare generated fromDevTemplatesrather than from literals inside the init command, so whatinitwrites and whatupdatecompares against cannot drift apart.
2.7.1 #
Features #
AppAudioPlayer(moarch create widget audio-player) — an audio player over just_audio that a screen configures rather than wires. It owns theAudioPlayer, loads the source and disposes both. OneAppAudioSourcecovers url, asset and file.- Every part is a switch, so the same widget is a podcast screen and a
voice-note bubble:
showControls,showSkip,showProgress,allowScrub,showTimes,showRemainingandshowSpeedare independent, andAppAudioPlayerStyle.compactis the one-row arrangement. - The skip buttons take durations, not a fixed 15/30 — the number is drawn inside the arrow, so any interval works without an icon per value.
- Buffered progress rides in the bar's secondary track; a scrub is not dragged
back by the position stream mid-drag; a finished clip restarts on the next
tap rather than sitting at the end; and
onCompletedfires once per play-through rather than on every frame the player sits incompleted.
- Every part is a switch, so the same widget is a podcast screen and a
voice-note bubble:
AppDragSection(moarch create widget drag-section) — a section whose children drag into a new order, vertical or horizontal, with no dependency.- It reports the move rather than owning the list, so the order can live
in a notifier, in storage or on a server without the widget holding a
second copy of it.
AppDragSection.reorderdoes the remove-and-insert. - Each item declares its own size —
AppDragSize.small/medium/largeoff a sharedAppDragSizes, or an exactextent— and whether it can be moved. - A pinned item is a wall, not merely un-draggable: it carries no drag listener at all, and nothing can be dropped past it, so an "add" tile keeps the last slot however the rest are shuffled.
onReorderarrives already corrected for theReorderableListViewoff-by-one and for any pinned item in the way.- A long press starts the drag, because an immediate listener over the whole
item fights the scroll;
AppDragTrigger.handleputs a grip on the trailing edge instead.
- It reports the move rather than owning the list, so the order can live
in a notifier, in storage or on a server without the widget holding a
second copy of it.
AppTable(moarch create widget table) — rows and columns sized for a phone, with no dependency.- Columns are fixed (
width) or flexible (flex), and a flexible one never squeezes below itsminWidth. Past the point where the minimums no longer fit, the table pans sideways rather than crushing the columns. AppTableColumn.numericright-aligns and switches on tabular figures.- Rows take
onTap,selectedand a colour of their own;striped,showRowDividers,showColumnDividers,showBorderanddensitydecide the rest. Cells are strings, orwidgetsfor a chip or an avatar. - It deliberately owns no vertical scroll — a table that scrolls
vertically cannot sit in a page that also does. Put it in
AppSingleScrollViewor aListView.
- Columns are fixed (
AppCountryPicker(moarch create widget country-picker) — the 238-countryAppCountrytable as a field of its own, validating like the rest of the family, or asAppCountryPicker.show(context)from anywhere that is not a form.- It hands back the whole
AppCountryrather than a code, since the caller usually wants the dial code or the flag too.displaypicks what the closed field reads as, andcountriesnarrows the list.
- It hands back the whole
Improvements #
- The country sheet is configured in one place.
AppPhoneInputcarried its ownSearchPickerSheetsetup — the flag leading each row, the calling code trailing it, the ranked search that makesPTfind Portugal rather than the first name containing those letters. That configuration now lives inAppCountryPicker.show, and the phone field opens it, so a standalone country field and a phone prefix cannot drift apart.phone-inputgainscountry-pickeras a dependency; the search sheet still arrives with it.
2.7.0 #
Features #
AppAudioPlayer(moarch create widget audio-player) — an audio player over just_audio that a screen configures rather than wires. It owns theAudioPlayer, loads the source and disposes both. OneAppAudioSourcecovers url, asset and file.- Every part is a switch, so the same widget is a podcast screen and a
voice-note bubble:
showControls,showSkip,showProgress,allowScrub,showTimes,showRemainingandshowSpeedare independent, andAppAudioPlayerStyle.compactis the one-row arrangement. - The skip buttons take durations, not a fixed 15/30 — the number is drawn inside the arrow, so any interval works without an icon per value.
- Buffered progress rides in the bar's secondary track; a scrub is not dragged
back by the position stream mid-drag; a finished clip restarts on the next
tap rather than sitting at the end; and
onCompletedfires once per play-through rather than on every frame the player sits incompleted.
- Every part is a switch, so the same widget is a podcast screen and a
voice-note bubble:
AppDragSection(moarch create widget drag-section) — a section whose children drag into a new order, vertical or horizontal, with no dependency.- It reports the move rather than owning the list, so the order can live
in a notifier, in storage or on a server without the widget holding a
second copy of it.
AppDragSection.reorderdoes the remove-and-insert. - Each item declares its own size —
AppDragSize.small/medium/largeoff a sharedAppDragSizes, or an exactextent— and whether it can be moved. - A pinned item is a wall, not merely un-draggable: it carries no drag listener at all, and nothing can be dropped past it, so an "add" tile keeps the last slot however the rest are shuffled.
onReorderarrives already corrected for theReorderableListViewoff-by-one and for any pinned item in the way.- A long press starts the drag, because an immediate listener over the whole
item fights the scroll;
AppDragTrigger.handleputs a grip on the trailing edge instead.
- It reports the move rather than owning the list, so the order can live
in a notifier, in storage or on a server without the widget holding a
second copy of it.
AppTable(moarch create widget table) — rows and columns sized for a phone, with no dependency.- Columns are fixed (
width) or flexible (flex), and a flexible one never squeezes below itsminWidth. Past the point where the minimums no longer fit, the table pans sideways rather than crushing the columns. AppTableColumn.numericright-aligns and switches on tabular figures.- Rows take
onTap,selectedand a colour of their own;striped,showRowDividers,showColumnDividers,showBorderanddensitydecide the rest. Cells are strings, orwidgetsfor a chip or an avatar. - It deliberately owns no vertical scroll — a table that scrolls
vertically cannot sit in a page that also does. Put it in
AppSingleScrollViewor aListView.
- Columns are fixed (
AppCountryPicker(moarch create widget country-picker) — the 238-countryAppCountrytable as a field of its own, validating like the rest of the family, or asAppCountryPicker.show(context)from anywhere that is not a form.- It hands back the whole
AppCountryrather than a code, since the caller usually wants the dial code or the flag too.displaypicks what the closed field reads as, andcountriesnarrows the list.
- It hands back the whole
Improvements #
- The country sheet is configured in one place.
AppPhoneInputcarried its ownSearchPickerSheetsetup — the flag leading each row, the calling code trailing it, the ranked search that makesPTfind Portugal rather than the first name containing those letters. That configuration now lives inAppCountryPicker.show, and the phone field opens it, so a standalone country field and a phone prefix cannot drift apart.phone-inputgainscountry-pickeras a dependency; the search sheet still arrives with it.
2.6.0 #
Features #
AppCalendar(moarch create widget calendar) — the inline month grid, for when the month itself is the content rather than one answer in a form.AppDateInputstill opens the platform picker; this is its sibling for agendas, booking screens and streaks. A wrapper over table_calendar that keeps its parameters out of your screens: colors come fromAppInputVariantlike the rest of the family, and the package is added topubspec.yamlfor you.eventsis re-keyed to the day each entry falls on. TwoDateTimes in one day are not equal, which is the usual reason a marker never appears — so you can pass the instants your data already carries, and two appointments at 09:00 and 14:00 count as two dots on one day rather than missing the grid.onMonthChangedreports the month's own bounds, not the six weeks drawn around it — the range to fetch events for. For the two-week and week formats it reports their own span.canChangeFormatoffers the month/2-week/week toggle, and only then is a vertical swipe live; without it a swipe means one thing.- No
onSelectedmakes it a read-only display, andselectableDaygreys out the days that refuse a tap. - It lives in its own
lib/shared/widgets/calendar/folder rather than alongside the fields.
AppActionSheet(moarch create widget action-sheet) — the sheet behind a three-dot button or a long press. Material rows on Android and the iOS grouped cards elsewhere, off the same platform splitAppDateInputuses for its pickers; either shape can be forced.- Rows resolve to a value, so
show<T>hands back what was picked andnullwhen it was dismissed — one honest "the user backed out" branch. - A row's
onTapruns after the sheet has closed, rather than while it is closing, where a handler that pushes a route fights the navigator for it. AppSheetAction.destructivedraws in the theme's error color. It confirms nothing on its own — pair it withAppConfirmDialogwhen the answer should be deliberate.- It takes a
BuildContextrather than the router's navigator key, unlikeAppDialogsandAppBottomModals, so it costs the project no GoRouter.
- Rows resolve to a value, so
Fixes #
moarch create model --emptygenerated a factory that could not compile. It patches<model>_entity.dart, whose class is<Model>Entity, but named the factory after the model alone —factory LoginResponse.empty() => LoginResponse(...)insideclass LoginResponseEntity. The guard that was meant to stop a second run looked for that same wrong name, so it never matched and every re-run stacked another broken factory into the file.- A field whose type carries a comma was silently dropped from
.empty()and fromcopyWith. The type was matched with a character class holding neither a comma nor a space, soMap<String, dynamic> meta;was not a field as far as the parser was concerned — and the factory it built came out missing a required argument. Types are now read up to the last identifier on the line and then validated, which also ends the false positives that class allowed:return value;in a method body was being read as a field namedvalueof typereturn, andString get title;as a field namedtitle. - An entity file declaring a second class had the two spliced together. The
parser took a class name and ignored it, reading every field in the file, so
AddressEntity's fields turned up inUserEntity'scopyWith. It now scopes to the named class's body — and so does the injection:create entity-copysappendedcopyWithand the==/hashCodepair at the file's last closing brace, landing them on whichever class was written last, after stripping the existing equality members from every class in the file. create empty-factoriesreported replacements it had not made. Its pattern only matches an arrow-bodied.empty(), so a hand-written block-bodied one fell throughreplaceFirstunchanged while the log claimed it had been replaced. It now leaves that factory alone and says so, and a factory already matching what would be written is reported as skipped — which is what theSkipped :line in the summary always claimed to count and never did.
2.5.1 #
Features #
AppAsyncView(moarch create widget async-view, generated byinit) — takes oneAsyncValueand draws the four states it can be in: a shimmered shape while the first load runs,ErrorViewwith a retry,EmptyViewwhen the screen says its data counts as empty, and your body when there is something to show. A reload over existing data leaves that data on screen rather than replacing a list mid-read with a spinner, and an error carrying no message of its own shows no detail instead of a stringified exception.ref.listenAction(...)(moarch create widget action-listener, generated byinit) — surfaces the one-shoterror/successfields a generated state already carries as anAppToast. PassonError/onSuccessto navigate or log instead; providing one replaces the toast for that outcome rather than adding to it, and a single action only ever reports one of the two.- The generated feature view is built on both.
moarch create featureused to write a.when(...)mapping by hand and leave// SHOW UI ERRORand// SHOW UI SUCCESSas comments in every feature. It now wires the two widgets up, passes its own body as the skeleton shape, and offers the retryErrorViewdraws a button for. It also writes both widgets if the project predates them, so the view it generates always compiles. AppMultiSelectInput(moarch create widget multi-select) —AppDropdownInput's plural: the same id/label entity list, any number selected, ticked in the search sheet with a per-row checkbox and a Done button. Shows its picks as removable chips, as labels, or as "3 selected"; enforcesrequired,minSelectedandmaxSelected, and stops the unticked rows at the ceiling rather than letting the form refuse the pick afterwards.SearchPickerSheet.showMulti(...)— the multi-select half of the sheet the dropdown and the country picker already open. It works on its own copy of the selection, so a dismissed sheet changes nothing and an empty result is a deliberate "none of them".AppDateRangeInput(moarch create widget date-range-input) — a read-only field holding a start and an end date, with amaxDaysrule the picker itself cannot express. It holds aDateTimeRangerather than the text of one.AppFilePickerField(moarch create widget file-input) — an attachment field: an area that opens whichever picker the app already uses, and a row per file with a thumbnail, a readable size and a remove button. It imports no picker package, so it costs the project no dependency it had not already chosen.AppRating(moarch create widget rating) — stars both ways round: tappable withonChanged, a read-only score without it. Halves come from tapping the left half of a star, and a display-only rating stays out ofForm.validate().AppTabs/AppTabBar(moarch create widget tabs) —AppTabsowns the controller and puts the views under the bar, replacing it when the tab count changes;AppTabBaris thePreferredSizeWidgethalf that drops intoAppAppBar'sbottomslot. Underline or pill indicator.AppDrawer(moarch create widget drawer) — the side menu, readingAppBottomNav's destination list, with header and footer slots. It closes itself after a pick, and does nothing when the same widget is pinned beside the content instead.AppNavRailandAppAdaptiveNav(moarch create widget nav-rail) — the vertical navigation a tablet shows instead of a bottom bar, and the scaffold that picks between them off the 600dp short-side breakpoint. All three nav widgets read oneAppNavDestinationlist.AppFab(moarch create widget fab) — the screen's floating action, circular or extended off one parameter, wearingAppButtonVariant/AppButtonTyperather than a vocabulary of its own.isLoadingswaps the icon for a spinner without resizing the button, andheroTagis exposed for the two-FABs-on-one-screen case.AppTimeline(moarch create widget timeline) — a vertical sequence of events joined by a connector, with done/current/pending/failed nodes.AppTimeline.entryBuilderhands you one row for a lazy list.AppCarousel(moarch create widget carousel) — swipeable pages with stretching dots, optional peek and auto-advance. The timer stops for good on the first swipe and never starts when the platform asks for reduced motion;AppCarouselDotsis usable on its own.
Fixes #
moarch initnever wrote its ownlib/main.dart.flutter createleaves one behind and generated files are never clobbered, so on the documented quick start (flutter create→moarch init) the counter demo survived and the scaffold's main.dart — the one that installsProviderScopeand initialises the selected services — was silently skipped. Every scaffolded app was missing its provider root. The counter demo is now replaced, matched on the two private names only that template declares; a main.dart you wrote is still left alone, and init says so instead of passing over it in silence. The counterwidget_test.dartthat pumped it is replaced on the same terms, soflutter testpasses on a fresh project.file_pickerresolved to 3.0.4 (2021) whenever the media service was selected, and 3.0.4 predates AGP'snamespacerequirement — so the Android build failed with "Namespace not specified" before the app could run. The entry was unversioned, and pub is free to resolve backwards:file_picker11 wantswin32 ^5,flutter_secure_storage_windowswantswin32 ^6, and walkingfile_pickerback to 3.0.4 settled that Windows-only conflict. It now carries a^11.0.0floor, andMediaServicecalls the staticFilePicker.pickFilesthat version moved to.- Three widgets used null-aware elements (
?header), which need the project's pubspec to ask for Dart 3.8+ — not merely a recent SDK to be installed — so they failed to compile in a project scaffolded a while ago. Rewritten to constructs with no language-version floor, and a test now fails if a template reaches for one again.
Improvements #
AppToastwas redrawn. It was a greysurfaceContainerHighestbar with a 4px accent stripe and an icon beside it — a Material 2 snackbar with a decoration. It is now a card: a surface tinted 7% with the status color, a status-colored outline, a soft shadow, and the icon in a tonal chip matchingAppLeadingIcon's. The outline is what the old one could not have — aSnackBartakes a color and a shape but not a border — so the toast now draws its own card inside a transparent, unelevated SnackBar. It also gains atitleover the detail line, an optional close button, awarning/infohelper to go withsuccess/error,AppToast.dismiss, a 480px ceiling so it stays a card rather than a banner on a tablet, and sideways swipe-to-dismiss. In dark themes it now sits onsurfaceContainerHighest— an overlay has to be lighter than the page it covers, and the old bar was darker than the content behind it.AppButton'shintmoved inside the button, centered under the label, in the button's own foreground color; the button grows to fit it. It used to be a left-aligned line floating above the button, which read as a caption for whatever was above it rather than as part of the action.- The design-system preview covers
AppPhoneInputandAppAsyncView— the phone field has been in the kit since 2.4.0 without a preview, and the async view's four states are steppable in it. A new test fails if a widget joins the catalog without either a preview section or an explicit, reasoned exemption, so the screen can no longer fall behind the kit unnoticed. moarch create featurerecords what it writes intoshared/widgets/in.moarch.yaml, somoarch updatecan tell those files apart from ones you have since edited.
2.5.0 #
Features #
AppAsyncView(moarch create widget async-view, generated byinit) — takes oneAsyncValueand draws the four states it can be in: a shimmered shape while the first load runs,ErrorViewwith a retry,EmptyViewwhen the screen says its data counts as empty, and your body when there is something to show. A reload over existing data leaves that data on screen rather than replacing a list mid-read with a spinner, and an error carrying no message of its own shows no detail instead of a stringified exception.ref.listenAction(...)(moarch create widget action-listener, generated byinit) — surfaces the one-shoterror/successfields a generated state already carries as anAppToast. PassonError/onSuccessto navigate or log instead; providing one replaces the toast for that outcome rather than adding to it, and a single action only ever reports one of the two.- The generated feature view is built on both.
moarch create featureused to write a.when(...)mapping by hand and leave// SHOW UI ERRORand// SHOW UI SUCCESSas comments in every feature. It now wires the two widgets up, passes its own body as the skeleton shape, and offers the retryErrorViewdraws a button for. It also writes both widgets if the project predates them, so the view it generates always compiles. AppMultiSelectInput(moarch create widget multi-select) —AppDropdownInput's plural: the same id/label entity list, any number selected, ticked in the search sheet with a per-row checkbox and a Done button. Shows its picks as removable chips, as labels, or as "3 selected"; enforcesrequired,minSelectedandmaxSelected, and stops the unticked rows at the ceiling rather than letting the form refuse the pick afterwards.SearchPickerSheet.showMulti(...)— the multi-select half of the sheet the dropdown and the country picker already open. It works on its own copy of the selection, so a dismissed sheet changes nothing and an empty result is a deliberate "none of them".AppDateRangeInput(moarch create widget date-range-input) — a read-only field holding a start and an end date, with amaxDaysrule the picker itself cannot express. It holds aDateTimeRangerather than the text of one.AppFilePickerField(moarch create widget file-input) — an attachment field: an area that opens whichever picker the app already uses, and a row per file with a thumbnail, a readable size and a remove button. It imports no picker package, so it costs the project no dependency it had not already chosen.AppRating(moarch create widget rating) — stars both ways round: tappable withonChanged, a read-only score without it. Halves come from tapping the left half of a star, and a display-only rating stays out ofForm.validate().AppTabs/AppTabBar(moarch create widget tabs) —AppTabsowns the controller and puts the views under the bar, replacing it when the tab count changes;AppTabBaris thePreferredSizeWidgethalf that drops intoAppAppBar'sbottomslot. Underline or pill indicator.AppDrawer(moarch create widget drawer) — the side menu, readingAppBottomNav's destination list, with header and footer slots. It closes itself after a pick, and does nothing when the same widget is pinned beside the content instead.AppNavRailandAppAdaptiveNav(moarch create widget nav-rail) — the vertical navigation a tablet shows instead of a bottom bar, and the scaffold that picks between them off the 600dp short-side breakpoint. All three nav widgets read oneAppNavDestinationlist.AppFab(moarch create widget fab) — the screen's floating action, circular or extended off one parameter, wearingAppButtonVariant/AppButtonTyperather than a vocabulary of its own.isLoadingswaps the icon for a spinner without resizing the button, andheroTagis exposed for the two-FABs-on-one-screen case.AppTimeline(moarch create widget timeline) — a vertical sequence of events joined by a connector, with done/current/pending/failed nodes.AppTimeline.entryBuilderhands you one row for a lazy list.AppCarousel(moarch create widget carousel) — swipeable pages with stretching dots, optional peek and auto-advance. The timer stops for good on the first swipe and never starts when the platform asks for reduced motion;AppCarouselDotsis usable on its own.
Improvements #
- The design-system preview covers
AppPhoneInputandAppAsyncView— the phone field has been in the kit since 2.4.0 without a preview, and the async view's four states are steppable in it. A new test fails if a widget joins the catalog without either a preview section or an explicit, reasoned exemption, so the screen can no longer fall behind the kit unnoticed. moarch create featurerecords what it writes intoshared/widgets/in.moarch.yaml, somoarch updatecan tell those files apart from ones you have since edited.
2.4.0 #
Features #
AppPhoneInput(moarch create widget phone-input) — a phone field that masks what is typed for the country it is set to, with a searchable country picker in its prefix. The field holds only the national number, so the calling code cannot be typed twice or deleted; read the joined-up value fromAppPhoneNumber.e164. Changing country re-masks the existing digits rather than clearing them.AppCountry(moarch create widget country) — a table of 238 countries with ISO code, calling code and every mask their numbering plan allows. Plans with more than one shape are kept as a list, so the mask widens as the number grows (Hungary 8–9 digits, Germany 10–13), and validation holds a number to those exact lengths instead of a 7-to-15 range. Flags are derived from the ISO code, so no assets ship with it.SearchPickerSheet(moarch create widget search-sheet) — a bottom sheet that picks one row out of a long list, with a search field above it. Opens scrolled to the current selection.AppDropdownInput— swaps the menu for that sheet once the list passesAppInputConfig.searchableThreshold(30), whichsearchable: true/falseoverrules per field. Both forms now validate:required: trueis enforced byForm.validate()rather than only marking the label, andvalidator/autovalidateModework as they do onAppInput. Also gainsonSelected(the picked entity, not just its id),onCleared(which puts a clear button in the field), and the sheet'sleadingOf,trailingLabelOf,filterandemptyLabel.moarch update— refreshes generated UI-kit widgets against the current templates. Files you never touched are refreshed automatically; files you edited are listed, diffed and left alone unless you pass--force..moarch.yaml— a manifest written byinitandcreate widgetrecording the moarch version, the selected stack and a hash of every generated file. It is what letsupdatetell an untouched file from an edited one.moarch doctor --fix— applies the fixes that don't need a decision.
Fixes #
AppDateInput/AppTimeInputshowed nothing without a caller-supplied controller: every value,initialValueand each picked one alike, was written only towidget.controller?.text. They now own a controller when none is passed (and dispose it), so the simplest possible usage displays its value. A controller that already holds text is no longer overwritten byinitialValueeither — the caller's value wins, as it does onAppInput.required: trueonAppDateInputandAppTimeInputonly drew an asterisk;Form.validate()passed an empty field. Both now validate, and take avalidator/autovalidateModelike the rest of the family.AppLoadingActionOverlaystarted its message timers only on a false-to-true change, so a screen that mounted with a request already in flight showed a bare spinner forever. They now start ininitStatetoo.AppSegmentedandAppChoiceChipdrew their selected foreground incolorScheme.surface, which is only the right answer in a light theme. Both now use the newAppInputStyle.onAccentOf, whichAppCheckboxandAppSwitchshare.
Improvements #
-
Selection controls validate.
AppCheckboxLabel(required: true)is the "accept the terms" checkbox aFormcan enforce, andAppRadioGroup(required: true)refuses to validate until one option is chosen. Both render the error under the control through the newSelectionFormField, which is exposed for wrapping any control of your own. -
AppSegmentedandAppRadioGroupassert that the current selection is actually one of the options, instead of silently rendering with nothing highlighted. -
AppCheckboxLabel,AppRadioGroup,AppSegmentedandAppChoiceChipall take a null callback to disable themselves, matchingAppCheckbox,AppSwitch,AppSliderandAppStepper.AppDateInputandAppTimeInputgainenabledalongside their existingreadOnly. -
AppStepper's − and + carry tooltips and semantics, and meet the 48px minimum tap target. -
moarch doctornow checks what the scaffold actually depends on: whetherbuild_runnerhas generatedapp_env.g.dart, whether both localization approaches ended up installed, whether every generated widget's dependencies and pub packages are present, and whether router-dependent widgets have a router. Findings carry hints, and say which are fixable.
2.3.0 #
Features #
AppPhoneInput(moarch create widget phone-input) — a phone field that masks what is typed for the country it is set to, with a searchable country picker in its prefix. The field holds only the national number, so the calling code cannot be typed twice or deleted; read the joined-up value fromAppPhoneNumber.e164. Changing country re-masks the existing digits rather than clearing them.AppCountry(moarch create widget country) — a table of 238 countries with ISO code, calling code and every mask their numbering plan allows. Plans with more than one shape are kept as a list, so the mask widens as the number grows (Hungary 8–9 digits, Germany 10–13), and validation holds a number to those exact lengths instead of a 7-to-15 range. Flags are derived from the ISO code, so no assets ship with it.SearchPickerSheet(moarch create widget search-sheet) — a bottom sheet that picks one row out of a long list, with a search field above it. Opens scrolled to the current selection.AppDropdownInput— swaps the menu for that sheet once the list passesAppInputConfig.searchableThreshold(30), whichsearchable: true/falseoverrules per field. Both forms now validate:required: trueis enforced byForm.validate()rather than only marking the label, andvalidator/autovalidateModework as they do onAppInput. Also gainsonSelected(the picked entity, not just its id),onCleared(which puts a clear button in the field), and the sheet'sleadingOf,trailingLabelOf,filterandemptyLabel.moarch update— refreshes generated UI-kit widgets against the current templates. Files you never touched are refreshed automatically; files you edited are listed, diffed and left alone unless you pass--force..moarch.yaml— a manifest written byinitandcreate widgetrecording the moarch version, the selected stack and a hash of every generated file. It is what letsupdatetell an untouched file from an edited one.moarch doctor --fix— applies the fixes that don't need a decision.
Fixes #
AppDateInput/AppTimeInputshowed nothing without a caller-supplied controller: every value,initialValueand each picked one alike, was written only towidget.controller?.text. They now own a controller when none is passed (and dispose it), so the simplest possible usage displays its value. A controller that already holds text is no longer overwritten byinitialValueeither — the caller's value wins, as it does onAppInput.required: trueonAppDateInputandAppTimeInputonly drew an asterisk;Form.validate()passed an empty field. Both now validate, and take avalidator/autovalidateModelike the rest of the family.AppLoadingActionOverlaystarted its message timers only on a false-to-true change, so a screen that mounted with a request already in flight showed a bare spinner forever. They now start ininitStatetoo.AppSegmentedandAppChoiceChipdrew their selected foreground incolorScheme.surface, which is only the right answer in a light theme. Both now use the newAppInputStyle.onAccentOf, whichAppCheckboxandAppSwitchshare.
Improvements #
-
Selection controls validate.
AppCheckboxLabel(required: true)is the "accept the terms" checkbox aFormcan enforce, andAppRadioGroup(required: true)refuses to validate until one option is chosen. Both render the error under the control through the newSelectionFormField, which is exposed for wrapping any control of your own. -
AppSegmentedandAppRadioGroupassert that the current selection is actually one of the options, instead of silently rendering with nothing highlighted. -
AppCheckboxLabel,AppRadioGroup,AppSegmentedandAppChoiceChipall take a null callback to disable themselves, matchingAppCheckbox,AppSwitch,AppSliderandAppStepper.AppDateInputandAppTimeInputgainenabledalongside their existingreadOnly. -
AppStepper's − and + carry tooltips and semantics, and meet the 48px minimum tap target. -
moarch doctornow checks what the scaffold actually depends on: whetherbuild_runnerhas generatedapp_env.g.dart, whether both localization approaches ended up installed, whether every generated widget's dependencies and pub packages are present, and whether router-dependent widgets have a router. Findings carry hints, and say which are fixable.
1.7.9 #
Features #
- easy_localization option (mutually exclusive with flutter_localizations)
- ios/Runner/Info.plist auto-patched: CFBundleLocalizations for localization options, camera/photo library/microphone usage descriptions for the media service, LSApplicationQueriesSchemes for the URL launcher, and UIBackgroundModes (fetch, remote-notification) for Firebase push (existing keys are never overwritten; rolled back on failure)
- ios/Runner/AppDelegate.swift auto-patched: UNUserNotificationCenter delegate wiring for the local notifications service (skipped when already present or customized; rolled back on failure)
- Firebase push generates Runner.entitlements + RunnerProfile.entitlements (aps-environment), and the build_ipa workflow signs the archive with them
- any Firebase option generates add_files_to_xcode.rb at the project root; build_ipa registers GoogleService-Info.plist in the Xcode project before compiling
- docs templates rewritten/corrected: GENERATE_JKS_FILE and STEPS_FOR_WORKFLOW are proper markdown (kts imports, secrets table, FCM push steps); security checklist pinning + logger examples fixed
1.6.5 #
Fixed #
Found by actually running moarch init --all + moarch create feature --all against a real flutter create project and checking flutter pub get / flutter analyze — several of these meant the documented quick-start flow didn't compile out of the box.
PubspecUtils._ensureSectioncorruptedpubspec.yaml. It misread the nestedsdk: flutterline underflutter:(present in everyflutter createproject) as the end of thedependencies:section, so all new dependencies were inserted in the wrong place and produced a duplicate YAML key that madeflutter pub getfail outright.- Generated
app_router.dartreferenced an undefinedauthNotifierProviderandAppRoutes.login(which is commented out by default) — a freshmoarch init --allproject never compiled. The auth-guard redirect is now documented as an opt-in commented example instead of active code. - Generated
dio_client.dartreferencedAppEnv.prodBaseUrl/AppEnv.devBaseUrl, which don't exist on the generatedAppEnv(onlybaseUrldoes). - Generated
safe_api_call.darthad a stray~character right after the opening string literal, which was a syntax error. - Generated
connectivity_service.dartimported a garbled path (core/utils/appappLogger.iger.dart) and called an undefined top-levellog()instead ofappLogger. - Generated
media_service.dartcalledFilePicker.pickFiles(...)statically;pickFilesis an instance method onFilePicker.platform. - Generated use case (
get_<name>.dart) imported acore/usecases/usecase.dartbase class that is never generated anywhere, and its import path torepository_impl.darthad one extra../. Use cases are now self-contained (no missing base class) with corrected import depth. - Generated repository interface/impl never declared the
getAll()method that the generated use case called against it. - Generated notifier (
<name>_notifier.dart) only imported the repository provider when "Use Cases" was not selected, soauthRepositoryProviderwas undefined whenever use cases were included (the notifier's_repogetter needs it either way). - Generated
<name>_remote_datasource.dartcalledsafeApiCallwithout importing the file that defines it. create feature <name>with the "Local/Cache Datasource" layer selected wrote the connectivity service to the wrong path and passed the wrong variable name into the generated datasource (swapped arguments).- Generated
AppImagewidget had a syntax error (?.isValidUrl != nullwith no receiver). - Generated
AppAvatar/AppImagewidgets checked a method tear-off instead of callingisValidUrl(), so an invalid URL was never actually detected.
Added #
- CI workflow (
dart analyze,dart format --set-exit-if-changed,dart test,dart pub publish --dry-run) on push/PR tomain. moarch doctorcommand to sanity-check an existing scaffolded project.--dry-runflag onmoarch initto preview generated files without writing them.--verboseflag to print stack traces on unexpected errors.- Per-item descriptions and a quit option (
q) in the interactive checklist prompt. - Real dark theme (
AppTheme.dark) instead of an empty stub, with matching dark color tokens inAppConstants. - Dark-mode variant in the generated
flutter_native_splash.yaml.
Changed #
initandcreate feature/create modelnow roll back files they created if scaffolding fails partway through, instead of leaving the target project in a half-generated state.initalso restores the originalpubspec.yamlon failure.- CLI version string is now read from a single source (
lib/src/version.dart) instead of being hardcoded inrunner.dart.
Known gaps (not addressed this round — out of scope) #
- The generated
test/test_helper.dartreferencesmocktail, which isn't declared as a dependency, so it doesn't compile as-is. Left untouched since testing scaffolding is handled by the separatemogen_unit_tests/mogen_integration_testspackages.
1.4.7 #
UPDATE #
- CREATING PUBSPEC WITH DEPS. FIX SOME OUTPUTS AND MINOR ERRORS. ADDED NOTIFICATIONS SERVICE AND LOCALIZATION CONFIG. README UPDATED
1.4.2 #
1.3.9 #
- added: documentation - public api
1.3.8 #
- added: documentation - public api
1.3.7 #
- fix: some ui adjustments. feat: 2 new security workflows. refactor: logger name for easy import
1.3.6 #
- feat: security checklist, loading action with messages
1.3.5 #
- feat: retry for dio
1.3.4 #
- fix: input, validation and dio adjustments
1.3.3 #
- fix: validation service
1.3.2 #
- feat: validation service (security)
1.3.1 #
- fix: throw app exception when this is private
1.3.0 #
- feat: media, urllauncher, connectivity service. firebase providers. option list on init command
1.2.3 #
- fix: app loading data for view
1.2.2 #
- fix: tests notifier
1.2.1 #
- fix: tests notifier
1.2.0 #
- fix: readme. fix: tests
1.1.20 #
- fix: readme. feat: simplifing tests using moktail
1.1.19 #
- fix: readme
1.1.18 #
- fix: imports
1.1.17 #
- fix: dio status code, test throws
1.1.16 #
- feat: flags for both unit and integration tests
1.1.15 #
- fix: imports, and other errors
1.1.14 #
- feat: hint, and icons for dropdown
1.1.13 #
- update: readme
1.1.12 #
- feat: text theme and loading action overlay
1.1.11 #
- feat: continue on error for integration pipeline, and dont block merge if warnings on analyze
1.1.10 #
- feat: logs, and error management
1.1.9 #
- feat: user interaction if want tests or not
1.1.8 #
- fix: imports on design system, wrong color on app theme. tests adjustments
1.1.7 #
- feat: separate the tests by folder
1.1.6 #
- fix: imports, and create command
1.1.5 #
- fix: not creating the integration test
1.1.4 #
- feat: flag for tests, fix: imports on test file
1.1.3 #
- feat: unit tests and integration tests (beta)
1.1.2 #
- feat: design system for preview, refactor: hint to hintText
1.1.1 #
- remove: hint style
1.1.0 #
- fix: colors, theme, sizes
1.0.15 #
- feat: new inputs (date, time, dropdown), new time extension. fix: minor bugs
1.0.14 #
- feat: app exception from dio error. fix: brightness on theme data
1.0.13 #
- feat: prod checklist file for better app development
1.0.12 #
- fix: readme
1.0.11 #
- fix: envied file and readme
1.0.10 #
- feat: new env package for security
1.0.9 #
- fix: readme
1.0.8 #
- feat: router
1.0.7 #
- fix: colors
1.0.6 #
- fix: input theme label
1.0.5 #
- fix: theme and constants
1.0.4 #
- fix: dio config
1.0.3 #
- fix: import in view and param in error view
1.0.2 #
- fix: input and btn the size of touch target
1.0.1 #
- feat: transparent type on btn, palette section for constants, theme light has brightness. refactor: error view for optional message.
1.0.0 #
- fix: shared widget import
0.1.9 #
- fix: view widget builder
0.1.8 #
- fix: model to entity -> from entity, refactor: some of the widgets folder structure and files
0.1.7 #
- fix: shared import
0.1.6 #
- fix: Notifier fixed import
0.1.5 #
- fix: Model cant be empty, AppInput missing app constants and wrong construct, on notifier fixed import
0.1.4 #
- fix: Model not writting, remove routepath from view. feat: added repo in notifier. refactor: removed abstract datasources for simplicity
0.1.3 #
- fix: Dio client, and create command checklist
0.1.2 #
- fix: AppButton imports and using wrong constants
- Added AppInput
0.1.1 #
- Readme adjustments
0.1.0 #
- Initial release
0.0.1 #
- TODO: Describe initial release.