refactor(client): 删除死代码 PlansScreen + NavView.plans + choosePlan l10n(Renew→Purchase 直达后无调用者)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -473,7 +473,6 @@ abstract class AppText {
|
||||
String get updateCheckFailed; // 检查失败(网络异常)
|
||||
|
||||
// ── 套餐选择 ──
|
||||
String get choosePlan;
|
||||
String get freePlan;
|
||||
String get proPlan;
|
||||
String get teamPlan;
|
||||
|
||||
@@ -250,8 +250,6 @@ class StringsEn extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => 'Update check failed, try again later';
|
||||
|
||||
@override
|
||||
String get choosePlan => 'Choose plan';
|
||||
@override
|
||||
String get freePlan => 'Free';
|
||||
@override
|
||||
|
||||
@@ -250,8 +250,6 @@ class StringsEs extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => 'Falló la búsqueda de actualizaciones, inténtalo más tarde';
|
||||
|
||||
@override
|
||||
String get choosePlan => 'Elegir plan';
|
||||
@override
|
||||
String get freePlan => 'Gratis';
|
||||
@override
|
||||
|
||||
@@ -250,8 +250,6 @@ class StringsJa extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => 'アップデートの確認に失敗しました。後でもう一度お試しください';
|
||||
|
||||
@override
|
||||
String get choosePlan => 'プランを選択';
|
||||
@override
|
||||
String get freePlan => '無料';
|
||||
@override
|
||||
|
||||
@@ -250,8 +250,6 @@ class StringsKo extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => '업데이트 확인에 실패했습니다. 잠시 후 다시 시도하세요';
|
||||
|
||||
@override
|
||||
String get choosePlan => '요금제 선택';
|
||||
@override
|
||||
String get freePlan => '무료';
|
||||
@override
|
||||
|
||||
@@ -250,8 +250,6 @@ class StringsRu extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => 'Не удалось проверить обновления, попробуйте позже';
|
||||
|
||||
@override
|
||||
String get choosePlan => 'Выбор тарифа';
|
||||
@override
|
||||
String get freePlan => 'Бесплатный';
|
||||
@override
|
||||
|
||||
@@ -249,8 +249,6 @@ class StringsZh extends AppText {
|
||||
@override
|
||||
String get updateCheckFailed => '检查更新失败,请稍后重试';
|
||||
|
||||
@override
|
||||
String get choosePlan => '选择套餐';
|
||||
@override
|
||||
String get freePlan => '免费版';
|
||||
@override
|
||||
|
||||
@@ -49,7 +49,6 @@ class DesktopShell extends ConsumerWidget {
|
||||
NavView.account: t.tabMe,
|
||||
NavView.contact: t.contactTitle,
|
||||
NavView.settings: t.settingsTitle,
|
||||
NavView.plans: t.choosePlan,
|
||||
NavView.redeem: t.redeemTitle,
|
||||
NavView.devices: t.myDevices,
|
||||
NavView.purchase: t.purchaseTitle,
|
||||
@@ -76,9 +75,6 @@ class DesktopShell extends ConsumerWidget {
|
||||
case NavView.settings:
|
||||
return const SettingsPage();
|
||||
// 账户下钻子页(内容区,顶栏带返回)
|
||||
case NavView.plans:
|
||||
// 只有 pro 走 pay v2 购买通道;team 等仍走既有兑换/联系人工流程。
|
||||
return PlansScreen(t: t, embedded: true, onChoose: (code) => go(code == 'pro' ? NavView.purchase : NavView.redeem));
|
||||
case NavView.redeem:
|
||||
return RedeemScreen(t: t, embedded: true);
|
||||
case NavView.devices:
|
||||
|
||||
@@ -3,11 +3,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
/// 一级视图 + 账户子页。
|
||||
/// desktop 侧栏暴露 6 个一级项(connect..settings);mobile/tablet 取前 4 项,
|
||||
/// contact/settings 在 mobile 走账户子页。plans/redeem 是 account 的下钻页。
|
||||
enum NavView { connect, servers, stats, account, contact, settings, plans, redeem, devices, purchase, payment, orders, invite, notifications }
|
||||
/// contact/settings 在 mobile 走账户子页。redeem 是 account 的下钻页。
|
||||
enum NavView { connect, servers, stats, account, contact, settings, redeem, devices, purchase, payment, orders, invite, notifications }
|
||||
|
||||
/// 账户下钻子页(desktop 在内容区切换、顶栏带返回;mobile/tablet 走全屏 push)。
|
||||
const Set<NavView> kAccountSubViews = {NavView.plans, NavView.redeem, NavView.devices, NavView.purchase, NavView.payment, NavView.orders, NavView.invite};
|
||||
const Set<NavView> kAccountSubViews = {NavView.redeem, NavView.devices, NavView.purchase, NavView.payment, NavView.orders, NavView.invite};
|
||||
|
||||
/// 当前视图。
|
||||
final navViewProvider = StateProvider<NavView>((ref) => NavView.connect);
|
||||
|
||||
@@ -20,7 +20,6 @@ import '../services/auth_api.dart';
|
||||
import '../state/account_providers.dart';
|
||||
import 'pangolin_button.dart';
|
||||
import 'pangolin_icons.dart';
|
||||
import 'plan_card.dart';
|
||||
|
||||
/// 通用:带返回箭头的子页骨架。embedded=true 时只返回内容(desktop 内容区下钻,
|
||||
/// 返回/标题由外层 shell 顶栏提供),否则整页 Scaffold(mobile/tablet 全屏 push)。
|
||||
@@ -67,66 +66,6 @@ class SettingsScreen extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
/// ── 套餐选择 ── (价格/额度来自 GET /v1/plans;当前档由 me.plan 判定;
|
||||
/// 功能清单仍取 l10n,后端无此字段)
|
||||
class PlansScreen extends ConsumerWidget {
|
||||
const PlansScreen({super.key, required this.t, this.onChoose, this.onBack, this.embedded = false});
|
||||
final AppText t;
|
||||
final ValueChanged<String>? onChoose;
|
||||
final VoidCallback? onBack;
|
||||
final bool embedded;
|
||||
|
||||
List<String> _feats(String code) => switch (code) {
|
||||
'free' => t.featsFree,
|
||||
'pro' => t.featsPro,
|
||||
'team' => t.featsTeam,
|
||||
_ => const [],
|
||||
};
|
||||
|
||||
// 套餐名是 UI 文案(后端 plans 表无名称列),按 code 取 l10n。
|
||||
String _name(String code) => switch (code) {
|
||||
'free' => t.freePlan,
|
||||
'pro' => t.proPlan,
|
||||
'team' => t.teamPlan,
|
||||
_ => code,
|
||||
};
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final c = context.pangolin;
|
||||
final plansAsync = ref.watch(plansProvider);
|
||||
final myPlan = ref.watch(meProvider).valueOrNull?.plan ?? 'free';
|
||||
|
||||
Widget body() => plansAsync.when(
|
||||
loading: () => const Center(child: Padding(padding: EdgeInsets.all(40), child: CircularProgressIndicator())),
|
||||
error: (_, __) => Center(
|
||||
child: Padding(padding: const EdgeInsets.all(40), child: Text(t.lang.loadFailedRetry, style: PangolinText.body.copyWith(color: c.fg3)))),
|
||||
data: (plans) => ListView(
|
||||
padding: const EdgeInsets.fromLTRB(20, 14, 20, 24),
|
||||
children: [
|
||||
for (final p in plans)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 14, top: p.code == 'pro' ? 12 : 0),
|
||||
child: PlanCard(
|
||||
name: _name(p.code),
|
||||
price: p.priceLabel(),
|
||||
period: t.perMonth,
|
||||
features: _feats(p.code),
|
||||
ctaLabel: p.code == myPlan ? t.current : (p.code == 'team' ? t.choose : t.upgrade),
|
||||
featured: p.code == 'pro',
|
||||
isCurrent: p.code == myPlan,
|
||||
popularLabel: p.code == 'pro' ? t.mostPopular : null,
|
||||
onPressed: () => onChoose?.call(p.code),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
return _SubScaffold(title: t.choosePlan, onBack: onBack, embedded: embedded, child: body());
|
||||
}
|
||||
}
|
||||
|
||||
/// ── 设备管理 ── (真实 GET /v1/me/devices;移除 = DELETE。本机高亮待 P6 设备 id)
|
||||
class DevicesScreen extends ConsumerWidget {
|
||||
const DevicesScreen({super.key, required this.t, this.onBack, this.embedded = false});
|
||||
|
||||
@@ -70,7 +70,6 @@ void main() {
|
||||
testWidgets('desktop 联系页', (t) => _shoot(t, NavView.contact, 'desktop_contact'));
|
||||
testWidgets('desktop 设置页', (t) => _shoot(t, NavView.settings, 'desktop_settings'));
|
||||
// 账户下钻子页(内容区 + 顶栏返回)
|
||||
testWidgets('desktop 套餐选择', (t) => _shoot(t, NavView.plans, 'desktop_plans'));
|
||||
testWidgets('desktop 兑换购买', (t) => _shoot(t, NavView.redeem, 'desktop_redeem'));
|
||||
testWidgets('desktop 设备管理', (t) => _shoot(t, NavView.devices, 'desktop_devices'));
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
Reference in New Issue
Block a user