- outfit_provider:方案列表/生成任务轮询(pending→planning→scoring→rendering→done)/详情/选定主方案/收藏 - outfit_page:日期范围 + 地点生成表单,生成中显示任务进度,方案列表卡片 - plan_viewer_page:PageView 手指滑动切换方案,穿衣清单(衣橱/新品标记)、发型发色、设为主方案/收藏 - plan_effect_page:效果图 3 视角(正面/侧面/背面)查看 - avatar_viewer:three_dart + flutter_gl 3D 渲染实现(自动旋转),GLB 资产未接入时占位展示,kEnable3D 开关 - avatar_viewer_page:化身查看页 + 重新构建 - 新增 /plan-viewer /plan-effect /avatar-viewer 路由
74 lines
2.8 KiB
Dart
74 lines
2.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
import 'package:fluttertoast/fluttertoast.dart';
|
|
|
|
import '../../shared/widgets/avatar_viewer.dart';
|
|
import '../../shared/widgets/loading_view.dart';
|
|
import 'avatar_provider.dart';
|
|
|
|
/// 3D 化身查看页
|
|
class AvatarViewerPage extends ConsumerWidget {
|
|
const AvatarViewerPage({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final avatar = ref.watch(avatarProvider);
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('我的 3D 化身')),
|
|
body: avatar.when(
|
|
loading: () => const LoadingView(text: '加载化身...'),
|
|
error: (e, _) => Center(child: Text('加载失败:$e')),
|
|
data: (a) => ListView(
|
|
padding: const EdgeInsets.all(16),
|
|
children: [
|
|
AvatarViewer(
|
|
glbUrl: a.glbUrl,
|
|
title: '我的 3D 化身',
|
|
subtitle: a.built
|
|
? '脸型模板 ${a.faceTemplateId} · 体型模板 ${a.bodyTemplateId} · 肤色 ${a.skinToneIndex}'
|
|
: '尚未构建化身',
|
|
),
|
|
const SizedBox(height: 12),
|
|
Card(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
const Text('构建说明',
|
|
style: TextStyle(
|
|
fontSize: 15, fontWeight: FontWeight.bold)),
|
|
const SizedBox(height: 8),
|
|
const Text(
|
|
'化身由脸型(20 档)× 体型(6 档)× 肤色(5 档)模板组合而成,'
|
|
'依据大头照、全身照与身形参数自动匹配。'
|
|
'3D 渲染在预烘焙 GLB 资产接入后启用。',
|
|
style: TextStyle(fontSize: 13, color: Colors.grey),
|
|
),
|
|
const SizedBox(height: 12),
|
|
SizedBox(
|
|
width: double.infinity,
|
|
child: OutlinedButton.icon(
|
|
onPressed: () async {
|
|
await ref
|
|
.read(avatarProvider.notifier)
|
|
.buildAvatar();
|
|
if (context.mounted) {
|
|
Fluttertoast.showToast(msg: '化身构建完成');
|
|
}
|
|
},
|
|
icon: const Icon(Icons.refresh),
|
|
label: const Text('重新构建化身'),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|