refactor(client): SubScaffold 六合一(视觉零变化)+ tablet 注释订正 + 平板通知铃入口(#20)

This commit is contained in:
wangjia
2026-07-13 10:07:18 +08:00
parent 3a8ff64921
commit a61641b53b
20 changed files with 108 additions and 150 deletions
+6 -19
View File
@@ -16,6 +16,7 @@ import '../widgets/page_body.dart';
import '../widgets/pangolin_button.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/pangolin_toast.dart';
import '../widgets/sub_scaffold.dart';
class InviteScreen extends ConsumerWidget {
const InviteScreen({super.key, required this.t, this.onBack, this.embedded = false});
@@ -59,7 +60,6 @@ class InviteScreen extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final c = context.pangolin;
final inviteAsync = ref.watch(inviteProvider);
Widget body = PageBody(child: inviteAsync.when(
@@ -70,24 +70,11 @@ class InviteScreen extends ConsumerWidget {
: _InviteContent(t: t, info: info, onCopy: _copy, onVerifyAndClaim: (ctx) => _verifyAndClaim(ctx, ref)),
));
if (embedded) return body;
return Scaffold(
backgroundColor: c.bg,
body: SafeArea(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 16, 10),
child: Row(children: [
IconButton(
onPressed: onBack ?? () => Navigator.of(context).maybePop(),
icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1),
),
Text(t.inviteTitle, style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
]),
),
Expanded(child: body),
]),
),
return SubScaffold(
title: t.inviteTitle,
onBack: onBack,
embedded: embedded,
child: body,
);
}
}
+7 -19
View File
@@ -7,9 +7,9 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import '../l10n/app_text.dart';
import '../pangolin_theme.dart';
import '../widgets/page_body.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/status_pill.dart';
import '../widgets/sub_scaffold.dart';
typedef _Notice = ({
IconData icon,
@@ -137,24 +137,12 @@ class NotificationsScreen extends ConsumerWidget {
],
);
if (embedded) return PageBody(child: content());
return Scaffold(
backgroundColor: c.bg,
body: SafeArea(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 16, 10),
child: Row(children: [
IconButton(
onPressed: onBack ?? () => Navigator.of(context).maybePop(),
icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1),
),
Text(t.notifTitle, style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
]),
),
Expanded(child: PageBody(child: content())),
]),
),
return SubScaffold(
title: t.notifTitle,
onBack: onBack,
embedded: embedded,
wrapPageBody: true,
child: content(),
);
}
}
+4 -35
View File
@@ -14,6 +14,7 @@ import '../pangolin_theme.dart';
import '../state/navigation_provider.dart';
import '../state/orders_provider.dart';
import '../widgets/page_body.dart';
import '../widgets/sub_scaffold.dart';
import '../widgets/pangolin_button.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/status_pill.dart';
@@ -58,38 +59,6 @@ String _fmtDateTime(DateTime d) {
return '${l.year}-${two(l.month)}-${two(l.day)} ${two(l.hour)}:${two(l.minute)}';
}
/// 带返回栏的子页骨架(embedded=true 只返回内容,返回/标题由外层 shell 顶栏提供)。
class _SubScaffold extends StatelessWidget {
const _SubScaffold({required this.title, required this.child, this.onBack, this.embedded = false});
final String title;
final Widget child;
final VoidCallback? onBack;
final bool embedded;
@override
Widget build(BuildContext context) {
final c = context.pangolin;
if (embedded) return PageBody(child: child);
return Scaffold(
backgroundColor: c.bg,
body: SafeArea(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 16, 10),
child: Row(children: [
IconButton(
onPressed: onBack ?? () => Navigator.of(context).maybePop(),
icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1),
),
Text(title, style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
]),
),
Expanded(child: PageBody(child: child)),
]),
),
);
}
}
/// 订单页入口:内部在「列表」与「详情」两屏间切换(与原型单帧同构)。
class OrdersScreen extends ConsumerStatefulWidget {
const OrdersScreen({super.key, required this.t, this.onBack, this.embedded = false});
@@ -196,7 +165,7 @@ class _OrderListView extends ConsumerWidget {
]),
);
return _SubScaffold(title: t.ordersTitle, onBack: onBack, embedded: embedded, child: content());
return SubScaffold(title: t.ordersTitle, onBack: onBack, embedded: embedded, wrapPageBody: true, child: content());
}
Widget _row(BuildContext context, PangolinScheme c, PayOrderSummary o, bool divider) {
@@ -289,7 +258,7 @@ class _OrderDetailView extends ConsumerWidget {
final expiresAt = detailAsync.valueOrNull?.expiresAt;
final pill = _statusPill(t, o.status);
// 内容区(mobile 套 _SubScaffold;desktop embedded 前置一条返回条回到列表)。
// 内容区(mobile 套 SubScaffold;desktop embedded 前置一条返回条回到列表)。
Widget summaryCard() => Container(
width: double.infinity,
decoration: BoxDecoration(
@@ -376,7 +345,7 @@ class _OrderDetailView extends ConsumerWidget {
Expanded(child: PageBody(child: body())),
]);
}
return _SubScaffold(title: t.orderDetailTitle, onBack: onBack, child: body());
return SubScaffold(title: t.orderDetailTitle, onBack: onBack, wrapPageBody: true, child: body());
}
Widget _kv(PangolinScheme c, String label, String value, {VoidCallback? onCopy}) {
+6 -19
View File
@@ -15,6 +15,7 @@ import '../state/payment_provider.dart';
import '../widgets/pangolin_button.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/pangolin_toast.dart';
import '../widgets/sub_scaffold.dart';
class PaymentScreen extends ConsumerStatefulWidget {
const PaymentScreen({super.key, required this.t, this.onBack, this.onDone, this.embedded = false});
@@ -311,25 +312,11 @@ class _PaymentScreenState extends ConsumerState<PaymentScreen> {
style: PangolinText.body.copyWith(color: c.fg3))),
};
if (embedded) return body;
return Scaffold(
backgroundColor: c.bg,
body: SafeArea(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 16, 10),
child: Row(children: [
IconButton(
onPressed: onBack ?? () => Navigator.of(context).maybePop(),
icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1),
),
Text(t.paymentTitle,
style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
]),
),
Expanded(child: body),
]),
),
return SubScaffold(
title: t.paymentTitle,
onBack: onBack,
embedded: embedded,
child: body,
);
}
}
+6 -19
View File
@@ -11,6 +11,7 @@ import '../pangolin_theme.dart';
import '../state/payment_provider.dart';
import '../widgets/page_body.dart';
import '../widgets/pangolin_icons.dart';
import '../widgets/sub_scaffold.dart';
import '../widgets/pangolin_toast.dart';
import '../widgets/plan_card.dart';
import '../widgets/seg_switch.dart';
@@ -133,25 +134,11 @@ class _PurchaseScreenState extends ConsumerState<PurchaseScreen> {
},
));
if (widget.embedded) return body;
return Scaffold(
backgroundColor: c.bg,
body: SafeArea(
child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Padding(
padding: const EdgeInsets.fromLTRB(8, 6, 16, 10),
child: Row(children: [
IconButton(
onPressed: widget.onBack ?? () => Navigator.of(context).maybePop(),
icon: Icon(PangolinIcons.arrowLeft, size: 22, color: c.fg1),
),
Text(t.purchaseTitle,
style: PangolinText.h3.copyWith(color: c.fg1, fontWeight: FontWeight.w700)),
]),
),
Expanded(child: body),
]),
),
return SubScaffold(
title: t.purchaseTitle,
onBack: widget.onBack,
embedded: widget.embedded,
child: body,
);
}
}