extension-action
Extracts screen handlers and bloc listeners into a part-of "*.action.dart" extension file
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Extracts screen handlers and bloc listeners into a part-of "*.action.dart" extension file
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Handles cross-feature BusEvent communication with EventBusManager in the Flutter base template
Implements BLoC state management using AppBlocBase, an abstract State hierarchy, and a freezed _StateData
Builds the data layer with Freezed DTOs, Retrofit clients, hive_ce local stores, and repositories wired through injectable
Reviews UI-layer changes — screens, blocs, widgets, routes — against the template's StateBase + AppBlocBase + fl_theme conventions
Adds and updates app strings through the CSV → ARB → generated localizations workflow
Scaffolds a new feature module under apps/main/lib/presentation/modules using the bundled module generator
| name | extension-action |
| description | Extracts screen handlers and bloc listeners into a part-of "*.action.dart" extension file |
| license | MIT |
| compatibility | all |
| metadata | {"audience":"flutter-developers","framework":"flutter","pattern":"extension-action"} |
_blocListener, onRefresh, navigation handlers, or form callbacks to an existing screen.<feature>_screen.dart // UI + state controllers + part 'feature.action.dart';
<feature>.action.dart // part of '<feature>_screen.dart';
// extension on _<Feature>ScreenState { ... }
feature.action.dart (note: dot, not underscore — matches generator output) is one library with the screen, so it can call private members of _<Feature>ScreenState.
<feature>_screen.dart:
import 'package:core/core.dart';
import 'package:flutter/material.dart';
import '../../../../l10n/localization_ext.dart';
import '../../../base/base.dart';
import '../bloc/<feature>_bloc.dart';
part '<feature>.action.dart';
class FeatureScreen extends StatefulWidget {
static String routeName = '/feature';
const FeatureScreen({super.key, this.args});
final FeatureArgs? args;
@override
State<FeatureScreen> createState() => _FeatureScreenState();
}
class _FeatureScreenState extends StateBase<FeatureScreen> {
final _refreshController = RefreshController(initialRefresh: true);
@override
FeatureBloc get bloc => BlocProvider.of(context);
late ThemeData _themeData;
TextTheme get textTheme => _themeData.textTheme;
@override
Widget build(BuildContext context) {
_themeData = context.theme;
return BlocListener<FeatureBloc, FeatureState>(
listener: _blocListener,
child: ScreenForm(
title: l10n.featureTitle,
child: SmartRefresher(
controller: _refreshController,
onRefresh: onRefresh,
child: const FeatureBody(),
),
),
);
}
}
<feature>.action.dart:
part of '<feature>_screen.dart';
extension on _FeatureScreenState {
void _blocListener(BuildContext context, FeatureState state) {
hideLoading();
_refreshController.refreshCompleted();
}
void onRefresh() {
final id = widget.args?.id ?? widget.args?.initial?.id;
if (id != null) {
bloc.add(GetFeatureEvent(id));
}
}
}
Action file (extension):
_blocListener(BuildContext, State) — side effects from state changes (hide loading, complete refresh, show dialog/snackbar, navigate).onRefresh, onLoadMore, onSubmit — handlers passed to widgets.context.goToX(...)).Screen file:
build, sub-Widget _buildX() helpers.initState / dispose.TextEditingController, GlobalKey, RefreshController declarations.bloc getter override.extension on _FeatureScreenState) in generated code; if you prefer a name, use <Feature>Action for greppability.onRefresh) when the screen passes them as callbacks, or private (_handleX) when only used inside the action file.part of line MUST be the first non-comment line of the action file.part 'feature.action.dart'; (note: dot) directive in <feature>_screen.dart.part of '<feature>_screen.dart'; is the first line of the action file._blocListener calls hideLoading() early so the screen-level loading delegate is unstuck on every state change.build logic in the action file.context.goToX calls inside build — keep them in the action file.