cd477ce81a
- 出入库详情抽屉:通过/拒绝/撤回/提交/结清/退单/确认定价/打印 全部不收抽屉, 操作完成后原地重拉单据刷新内容(StatefulBuilder+refresh);仅 遮罩/X/ 修改·删除(离开语义)关闭——对齐拍板「点抽屉外才收回」 - 往来抽屉「编辑」、财务往来抽屉「登记收款/付款」(完成后流水原地刷新)、 商品编辑抽屉「保存」同规则;「取消」保持关闭语义 - 日期组件输入框 forceStrutHeight 锁行盒:修等宽字体 ascent/descent 不对称 导致的文字垂直偏移 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
629 lines
20 KiB
Dart
629 lines
20 KiB
Dart
// widgets/wheel_date_picker.dart — 统一日期选择组件(扁平风格,2026-07-04 拍板)。
|
||
//
|
||
// 形态(桌面=锚定下拉、窄屏=底部 sheet,内容同一套窗格):
|
||
// - 单日期 showDsDateDropdown:面板 = 可输入框 + 三列滚轮 + 底栏(今天/确定)
|
||
// - 范围 showDateRangeDropdown:起始|结束 两窗格并排(窄屏纵排)+ 共用底栏(预览/确定)
|
||
// 窗格(_DatePane):输入框与滚轮同宽(248)、文字水平垂直居中、mono;键入/回车/失焦
|
||
// 归一 yyyy-MM-dd 并联动滚轮,滚轮滚动实时回写输入框。全程无阴影/立体效果。
|
||
//
|
||
// 所有日期选择统一走本组件:录单日期格 DsDateCell、登记收支 DatePickerField、
|
||
// 列表时间范围(工具栏/详搜)。滚轮本体对齐原型 datewheel.js 三列结构。
|
||
import 'dart:math' as math;
|
||
|
||
import 'package:flutter/material.dart';
|
||
|
||
import '../core/responsive/responsive.dart';
|
||
import '../core/theme/context_tokens.dart';
|
||
import '../core/theme/app_tokens.dart';
|
||
import '../core/theme/app_dims.g.dart';
|
||
import '../core/utils/date_util.dart';
|
||
import '../core/theme/app_fonts.dart';
|
||
import 'ds/m_sheet.dart';
|
||
|
||
const double _kItem = 36; // .wheel-item 行高
|
||
const double _kColsH = 180; // .wheel-cols 高度(5 行)
|
||
const double _kWidth = 248; // 窗格宽度(输入框与滚轮同宽)
|
||
|
||
String _pad2(int n) => n.toString().padLeft(2, '0');
|
||
int _daysIn(int y, int m) => DateTime(y, m + 1, 0).day; // m: 1-12
|
||
|
||
// ═══════════════ 对外入口 ═══════════════
|
||
|
||
/// 单日期选择:桌面锚定 [anchorContext] 下方的下拉(透明遮罩点外关闭,不冻结窗口);
|
||
/// 窄屏底部 sheet。确定返回日期,点外部/取消返回 null。
|
||
Future<DateTime?> showDsDateDropdown(
|
||
BuildContext anchorContext, {
|
||
DateTime? initial,
|
||
String title = '选择日期',
|
||
}) {
|
||
if (anchorContext.isMobile) {
|
||
return showMSheet<DateTime>(
|
||
anchorContext,
|
||
title: title,
|
||
builder: (ctx) => Center(
|
||
child: _SingleDateBody(
|
||
initial: initial ?? DateTime.now(),
|
||
onCommit: (d) => Navigator.of(ctx).pop(d),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
return Navigator.of(anchorContext).push<DateTime>(_DropdownRoute<DateTime>(
|
||
anchorRect: _anchorRect(anchorContext),
|
||
builder: (ctx) => _DropCard(
|
||
child: _SingleDateBody(
|
||
initial: initial ?? DateTime.now(),
|
||
onCommit: (d) => Navigator.of(ctx).pop(d),
|
||
),
|
||
),
|
||
));
|
||
}
|
||
|
||
/// 日期范围选择:桌面锚定下拉(起始|结束并排);窄屏底部 sheet(纵排)。
|
||
/// 确定返回 DateTimeRange(起止倒置自动交换),点外部/取消返回 null。
|
||
Future<DateTimeRange?> showDateRangeDropdown(
|
||
BuildContext anchorContext, {
|
||
DateTimeRange? initial,
|
||
}) {
|
||
if (anchorContext.isMobile) {
|
||
return showMSheet<DateTimeRange>(
|
||
anchorContext,
|
||
title: '日期区间',
|
||
builder: (ctx) => Center(
|
||
child: _RangeBody(
|
||
initial: initial,
|
||
vertical: true,
|
||
onCommit: (r) => Navigator.of(ctx).pop(r),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
return Navigator.of(anchorContext)
|
||
.push<DateTimeRange>(_DropdownRoute<DateTimeRange>(
|
||
anchorRect: _anchorRect(anchorContext),
|
||
builder: (ctx) => _DropCard(
|
||
child: _RangeBody(
|
||
initial: initial,
|
||
vertical: false,
|
||
onCommit: (r) => Navigator.of(ctx).pop(r),
|
||
),
|
||
),
|
||
));
|
||
}
|
||
|
||
Rect _anchorRect(BuildContext anchorContext) {
|
||
final overlay = Navigator.of(anchorContext)
|
||
.overlay!
|
||
.context
|
||
.findRenderObject() as RenderBox;
|
||
final box = anchorContext.findRenderObject() as RenderBox?;
|
||
return box == null
|
||
? Rect.zero
|
||
: box.localToGlobal(Offset.zero, ancestor: overlay) & box.size;
|
||
}
|
||
|
||
// ═══════════════ 下拉路由(锚定,透明遮罩)═══════════════
|
||
|
||
class _DropdownRoute<T> extends PopupRoute<T> {
|
||
final Rect anchorRect;
|
||
final WidgetBuilder builder;
|
||
_DropdownRoute({required this.anchorRect, required this.builder});
|
||
|
||
@override
|
||
Color? get barrierColor => Colors.transparent;
|
||
@override
|
||
bool get barrierDismissible => true;
|
||
@override
|
||
String? get barrierLabel => 'date-dropdown';
|
||
@override
|
||
Duration get transitionDuration => Duration.zero;
|
||
|
||
@override
|
||
Widget buildPage(BuildContext context, Animation<double> animation,
|
||
Animation<double> secondaryAnimation) {
|
||
return CustomSingleChildLayout(
|
||
delegate: _DropdownLayout(anchorRect),
|
||
child: builder(context),
|
||
);
|
||
}
|
||
}
|
||
|
||
class _DropdownLayout extends SingleChildLayoutDelegate {
|
||
final Rect anchor;
|
||
_DropdownLayout(this.anchor);
|
||
|
||
@override
|
||
BoxConstraints getConstraintsForChild(BoxConstraints constraints) =>
|
||
BoxConstraints(
|
||
maxWidth: math.max(0, constraints.maxWidth - 16),
|
||
maxHeight: math.max(0, constraints.maxHeight - 16),
|
||
);
|
||
|
||
@override
|
||
Offset getPositionForChild(Size size, Size childSize) {
|
||
final left = anchor.left
|
||
.clamp(8.0, math.max(8.0, size.width - childSize.width - 8))
|
||
.toDouble();
|
||
final below = anchor.bottom + 6;
|
||
final above = anchor.top - childSize.height - 6;
|
||
final top = (below + childSize.height <= size.height - 8 || above < 8)
|
||
? below
|
||
: above;
|
||
return Offset(left, top.clamp(8.0, math.max(8.0, size.height - 8)));
|
||
}
|
||
|
||
@override
|
||
bool shouldRelayout(_DropdownLayout old) => old.anchor != anchor;
|
||
}
|
||
|
||
/// 下拉卡壳(扁平):surface + 1px 边框 + r-lg,无阴影。
|
||
class _DropCard extends StatelessWidget {
|
||
final Widget child;
|
||
const _DropCard({required this.child});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
return Material(
|
||
color: t.surface,
|
||
shape: RoundedRectangleBorder(
|
||
side: BorderSide(color: t.border),
|
||
borderRadius: BorderRadius.circular(AppDims.rLg),
|
||
),
|
||
child: Padding(padding: const EdgeInsets.all(12), child: child),
|
||
);
|
||
}
|
||
}
|
||
|
||
// ═══════════════ 单日期面板体 ═══════════════
|
||
|
||
class _SingleDateBody extends StatefulWidget {
|
||
final DateTime initial;
|
||
final ValueChanged<DateTime> onCommit;
|
||
const _SingleDateBody({required this.initial, required this.onCommit});
|
||
|
||
@override
|
||
State<_SingleDateBody> createState() => _SingleDateBodyState();
|
||
}
|
||
|
||
class _SingleDateBodyState extends State<_SingleDateBody> {
|
||
late DateTime _value = widget.initial;
|
||
int _paneEpoch = 0; // 「今天」时驱动窗格重建吸附
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
return Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
_DatePane(
|
||
key: ValueKey('single-$_paneEpoch'),
|
||
value: _value,
|
||
onChanged: (d) => _value = d,
|
||
),
|
||
// 底栏(扁平):今天(左)/ 确定(右)
|
||
Container(
|
||
width: _kWidth,
|
||
margin: const EdgeInsets.only(top: 10),
|
||
padding: const EdgeInsets.only(top: 10),
|
||
decoration: BoxDecoration(
|
||
border: Border(top: BorderSide(color: t.borderSubtle)),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
InkWell(
|
||
onTap: () => setState(() {
|
||
_value = DateTime.now();
|
||
_paneEpoch++;
|
||
}),
|
||
borderRadius: BorderRadius.circular(AppDims.rSm),
|
||
child: Padding(
|
||
padding:
|
||
const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||
child: Text('今天',
|
||
style: TextStyle(fontSize: AppDims.fsSm, color: t.muted)),
|
||
),
|
||
),
|
||
const Spacer(),
|
||
_CommitButton(onTap: () => widget.onCommit(_value)),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
// ═══════════════ 范围面板体 ═══════════════
|
||
|
||
class _RangeBody extends StatefulWidget {
|
||
final DateTimeRange? initial;
|
||
final bool vertical; // 窄屏纵排
|
||
final ValueChanged<DateTimeRange> onCommit;
|
||
const _RangeBody(
|
||
{this.initial, required this.vertical, required this.onCommit});
|
||
|
||
@override
|
||
State<_RangeBody> createState() => _RangeBodyState();
|
||
}
|
||
|
||
class _RangeBodyState extends State<_RangeBody> {
|
||
late DateTime _start = widget.initial?.start ?? DateTime.now();
|
||
late DateTime _end = widget.initial?.end ?? DateTime.now();
|
||
|
||
void _commit() {
|
||
widget.onCommit(_end.isBefore(_start)
|
||
? DateTimeRange(start: _end, end: _start)
|
||
: DateTimeRange(start: _start, end: _end));
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
final startPane = _DatePane(
|
||
title: '起始日期',
|
||
value: _start,
|
||
onChanged: (d) => setState(() => _start = d),
|
||
);
|
||
final endPane = _DatePane(
|
||
title: '结束日期',
|
||
value: _end,
|
||
onChanged: (d) => setState(() => _end = d),
|
||
);
|
||
final footerWidth = widget.vertical ? _kWidth : _kWidth * 2 + 12; // 与窗格区同宽
|
||
return Column(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.center,
|
||
children: [
|
||
if (widget.vertical) ...[
|
||
startPane,
|
||
const SizedBox(height: 14),
|
||
endPane,
|
||
] else
|
||
Row(
|
||
mainAxisSize: MainAxisSize.min,
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [startPane, const SizedBox(width: 12), endPane],
|
||
),
|
||
// 共用底栏(扁平):范围预览(左)/ 确定(右)
|
||
Container(
|
||
width: footerWidth,
|
||
margin: const EdgeInsets.only(top: 10),
|
||
padding: const EdgeInsets.only(top: 10),
|
||
decoration: BoxDecoration(
|
||
border: Border(top: BorderSide(color: t.borderSubtle)),
|
||
),
|
||
child: Row(
|
||
children: [
|
||
Expanded(
|
||
child: Text(
|
||
'${formatYmd(_start)} ~ ${formatYmd(_end)}',
|
||
style: TextStyle(
|
||
fontSize: AppDims.fsSm,
|
||
color: t.muted,
|
||
fontFamily: AppFonts.mono,
|
||
fontFamilyFallback: AppFonts.monoFallback),
|
||
),
|
||
),
|
||
_CommitButton(onTap: _commit),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
);
|
||
}
|
||
}
|
||
|
||
class _CommitButton extends StatelessWidget {
|
||
final VoidCallback onTap;
|
||
const _CommitButton({required this.onTap});
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
return InkWell(
|
||
onTap: onTap,
|
||
borderRadius: BorderRadius.circular(AppDims.rSm),
|
||
child: Container(
|
||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 5),
|
||
decoration: BoxDecoration(
|
||
color: t.primary,
|
||
borderRadius: BorderRadius.circular(AppDims.rSm),
|
||
),
|
||
child: Text('确定',
|
||
style: TextStyle(
|
||
fontSize: AppDims.fsSm,
|
||
color: t.onPrimary,
|
||
fontWeight: FontWeight.w600)),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
// ═══════════════ 窗格:可输入框 + 三列滚轮(同宽 248,扁平)═══════════════
|
||
|
||
class _DatePane extends StatefulWidget {
|
||
final String? title;
|
||
final DateTime value;
|
||
final ValueChanged<DateTime> onChanged;
|
||
const _DatePane(
|
||
{super.key, this.title, required this.value, required this.onChanged});
|
||
|
||
@override
|
||
State<_DatePane> createState() => _DatePaneState();
|
||
}
|
||
|
||
class _DatePaneState extends State<_DatePane> {
|
||
late final TextEditingController _ctrl =
|
||
TextEditingController(text: formatYmd(widget.value));
|
||
final FocusNode _focus = FocusNode();
|
||
late DateTime _wheelAnchor = widget.value; // 键入生效时驱动滚轮重建吸附
|
||
bool _syncing = false; // 滚轮回写输入框时跳过 onChanged 循环
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_focus.addListener(() {
|
||
if (!_focus.hasFocus) {
|
||
// 失焦归一显示(2024 → 2024-01-01)并吸附滚轮;无效则回显当前值
|
||
final n = normalizeYmd(_ctrl.text);
|
||
_setText(n ?? formatYmd(_wheelAnchor));
|
||
if (n != null) _applyTyped(n);
|
||
}
|
||
if (mounted) setState(() {});
|
||
});
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_ctrl.dispose();
|
||
_focus.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
void _setText(String v) {
|
||
_syncing = true;
|
||
_ctrl.text = v;
|
||
_syncing = false;
|
||
}
|
||
|
||
void _applyTyped(String ymd) {
|
||
final d = parseYmd(ymd);
|
||
if (d == null) return;
|
||
widget.onChanged(d);
|
||
if (d != _wheelAnchor) setState(() => _wheelAnchor = d);
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
return SizedBox(
|
||
width: _kWidth,
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||
children: [
|
||
if (widget.title != null)
|
||
Padding(
|
||
padding: const EdgeInsets.only(left: 2, bottom: 6),
|
||
child: Text(widget.title!,
|
||
style: TextStyle(
|
||
fontSize: AppDims.fsSm,
|
||
fontWeight: FontWeight.w600,
|
||
color: t.muted)),
|
||
),
|
||
// 输入框:与滚轮同宽、文字水平垂直居中、mono、扁平
|
||
Container(
|
||
height: 34,
|
||
margin: const EdgeInsets.only(bottom: 6),
|
||
decoration: BoxDecoration(
|
||
color: t.surface,
|
||
border: Border.all(color: _focus.hasFocus ? t.primary : t.border),
|
||
borderRadius: BorderRadius.circular(AppDims.rMd),
|
||
),
|
||
child: Center(
|
||
child: TextField(
|
||
controller: _ctrl,
|
||
focusNode: _focus,
|
||
keyboardType: TextInputType.datetime,
|
||
textAlign: TextAlign.center,
|
||
// 强制 strut 统一行盒(等宽字体 ascent/descent 不对称会让文字
|
||
// 视觉偏离垂直中心;height:1 行高=字号,Center 精确居中)
|
||
strutStyle: const StrutStyle(
|
||
fontSize: AppDims.fsBody,
|
||
height: 1.0,
|
||
forceStrutHeight: true,
|
||
),
|
||
style: TextStyle(
|
||
fontSize: AppDims.fsBody,
|
||
height: 1.0,
|
||
color: t.text,
|
||
fontFamily: AppFonts.mono,
|
||
fontFamilyFallback: AppFonts.monoFallback),
|
||
decoration: InputDecoration(
|
||
isCollapsed: true,
|
||
border: InputBorder.none,
|
||
enabledBorder: InputBorder.none,
|
||
focusedBorder: InputBorder.none,
|
||
filled: false,
|
||
hintText: '年-月-日',
|
||
hintStyle:
|
||
TextStyle(fontSize: AppDims.fsBody, color: t.faint),
|
||
),
|
||
onChanged: (v) {
|
||
if (_syncing) return;
|
||
// 键入完整日期(≥8 位)即联动滚轮;不完整先不动
|
||
final n = normalizeYmd(v);
|
||
if (n != null && v.trim().length >= 8) _applyTyped(n);
|
||
},
|
||
onSubmitted: (v) {
|
||
final n = normalizeYmd(v);
|
||
if (n != null) {
|
||
_setText(n);
|
||
_applyTyped(n);
|
||
}
|
||
},
|
||
),
|
||
),
|
||
),
|
||
_WheelCols(
|
||
key: ValueKey(formatYmd(_wheelAnchor)),
|
||
initial: _wheelAnchor,
|
||
onChanged: (d) {
|
||
widget.onChanged(d);
|
||
_setText(formatYmd(d));
|
||
},
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
// ═══════════════ 三列滚轮(扁平;对齐原型 datewheel.js 三列结构)═══════════════
|
||
|
||
class _WheelCols extends StatefulWidget {
|
||
final DateTime initial;
|
||
final ValueChanged<DateTime> onChanged;
|
||
const _WheelCols({super.key, required this.initial, required this.onChanged});
|
||
|
||
@override
|
||
State<_WheelCols> createState() => _WheelColsState();
|
||
}
|
||
|
||
class _WheelColsState extends State<_WheelCols> {
|
||
late final List<int> _years; // now-15 .. now+2(对齐 datewheel.js)
|
||
late int _yIdx, _mIdx, _dIdx;
|
||
late final FixedExtentScrollController _yCtrl, _mCtrl, _dCtrl;
|
||
|
||
int get _year => _years[_yIdx];
|
||
int get _month => _mIdx + 1;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
final now = DateTime.now();
|
||
_years = [for (var y = now.year - 15; y <= now.year + 2; y++) y];
|
||
final v = widget.initial;
|
||
_yIdx = _years.indexOf(v.year);
|
||
if (_yIdx < 0) _yIdx = _years.indexOf(now.year);
|
||
if (_yIdx < 0) _yIdx = 0;
|
||
_mIdx = (v.month - 1).clamp(0, 11);
|
||
_dIdx = (v.day - 1).clamp(0, _daysIn(v.year, v.month) - 1);
|
||
_yCtrl = FixedExtentScrollController(initialItem: _yIdx);
|
||
_mCtrl = FixedExtentScrollController(initialItem: _mIdx);
|
||
_dCtrl = FixedExtentScrollController(initialItem: _dIdx);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_yCtrl.dispose();
|
||
_mCtrl.dispose();
|
||
_dCtrl.dispose();
|
||
super.dispose();
|
||
}
|
||
|
||
void _emit() => widget.onChanged(DateTime(_year, _month, _dIdx + 1));
|
||
|
||
// 年/月变化后重算当月天数,超界则回夹并吸附。
|
||
void _onYearOrMonth() {
|
||
final n = _daysIn(_year, _month);
|
||
if (_dIdx > n - 1) {
|
||
_dIdx = n - 1;
|
||
_dCtrl.jumpToItem(_dIdx);
|
||
}
|
||
setState(() {});
|
||
_emit();
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
final t = context.tokens;
|
||
final days = _daysIn(_year, _month);
|
||
// 扁平:仅 1px 边框 + 圆角,无阴影/立体
|
||
return Container(
|
||
padding: const EdgeInsets.all(4),
|
||
decoration: BoxDecoration(
|
||
border: Border.all(color: t.border),
|
||
borderRadius: BorderRadius.circular(AppDims.rMd),
|
||
),
|
||
child: SizedBox(
|
||
height: _kColsH,
|
||
child: Stack(
|
||
children: [
|
||
Positioned(
|
||
left: 4,
|
||
right: 4,
|
||
top: (_kColsH - _kItem) / 2,
|
||
height: _kItem,
|
||
child: IgnorePointer(
|
||
child: Container(
|
||
decoration: BoxDecoration(
|
||
color: t.bg,
|
||
borderRadius: BorderRadius.circular(AppDims.rMd),
|
||
),
|
||
),
|
||
),
|
||
),
|
||
Row(
|
||
children: [
|
||
_col(t, _yCtrl, _years.length, (i) => _years[i].toString(),
|
||
_yIdx, (i) {
|
||
_yIdx = i;
|
||
_onYearOrMonth();
|
||
}),
|
||
_col(t, _mCtrl, 12, (i) => _pad2(i + 1), _mIdx, (i) {
|
||
_mIdx = i;
|
||
_onYearOrMonth();
|
||
}),
|
||
_col(t, _dCtrl, days, (i) => _pad2(i + 1), _dIdx, (i) {
|
||
setState(() => _dIdx = i);
|
||
_emit();
|
||
}),
|
||
],
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Widget _col(
|
||
AppTokens t,
|
||
FixedExtentScrollController ctrl,
|
||
int count,
|
||
String Function(int) label,
|
||
int selIdx,
|
||
ValueChanged<int> onSel,
|
||
) {
|
||
return Expanded(
|
||
child: ListWheelScrollView.useDelegate(
|
||
controller: ctrl,
|
||
itemExtent: _kItem,
|
||
physics: const FixedExtentScrollPhysics(),
|
||
diameterRatio: 100, // 近似平面,去掉滚轮弧度
|
||
perspective: 0.0001,
|
||
onSelectedItemChanged: onSel,
|
||
childDelegate: ListWheelChildBuilderDelegate(
|
||
childCount: count,
|
||
builder: (c, i) {
|
||
final on = i == selIdx;
|
||
return Center(
|
||
child: Text(
|
||
label(i),
|
||
style: TextStyle(
|
||
fontFamily: AppFonts.mono,
|
||
fontFamilyFallback: AppFonts.monoFallback,
|
||
fontSize: on ? 16 : AppDims.fsBody,
|
||
fontWeight: on ? FontWeight.w700 : FontWeight.w400,
|
||
color: on ? t.primary : t.muted,
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|