git-subtree-dir: app git-subtree-mainline:6ebd902c6bgit-subtree-split:a11a668869
126 lines
4.8 KiB
Dart
126 lines
4.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
|
|
import '../../core/ads/ads_service.dart';
|
|
import '../../core/config/app_config.dart';
|
|
import '../../shared/widgets/empty_view.dart';
|
|
import '../../shared/widgets/loading_view.dart';
|
|
import 'outfit_provider.dart';
|
|
|
|
const _angleLabels = {
|
|
'front': '正面',
|
|
'side': '侧面',
|
|
'back': '背面',
|
|
};
|
|
|
|
/// 效果图查看:3 视角(正面/侧面/背面)切换
|
|
class PlanEffectPage extends ConsumerStatefulWidget {
|
|
final List<PlanEffectImageInfo> images;
|
|
|
|
const PlanEffectPage({super.key, required this.images});
|
|
|
|
@override
|
|
ConsumerState<PlanEffectPage> createState() => _PlanEffectPageState();
|
|
}
|
|
|
|
class _PlanEffectPageState extends ConsumerState<PlanEffectPage> {
|
|
String? _selected; // 当前角度,null = 展示全部
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final done = widget.images.where((i) => i.done).toList();
|
|
final pending = widget.images.where((i) => !i.done).toList();
|
|
final angles = widget.images.map((i) => i.angle).toSet();
|
|
final ads = ref.watch(adsServiceProvider);
|
|
|
|
return Scaffold(
|
|
appBar: AppBar(title: const Text('效果图')),
|
|
body: Column(
|
|
children: [
|
|
if (angles.length > 1)
|
|
SizedBox(
|
|
height: 48,
|
|
child: ListView(
|
|
scrollDirection: Axis.horizontal,
|
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: 8),
|
|
child: ChoiceChip(
|
|
label: const Text('全部'),
|
|
selected: _selected == null,
|
|
onSelected: (_) => setState(() => _selected = null),
|
|
),
|
|
),
|
|
for (final a in angles)
|
|
Padding(
|
|
padding: const EdgeInsets.only(right: 8),
|
|
child: ChoiceChip(
|
|
label: Text(_angleLabels[a] ?? a),
|
|
selected: _selected == a,
|
|
onSelected: (_) => setState(() => _selected = a),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
Expanded(
|
|
child: done.isEmpty
|
|
? (pending.isEmpty
|
|
? const EmptyView(
|
|
message: '暂无效果图,选定主方案后自动生成(每日限 3 次)')
|
|
: const LoadingView(text: '效果图生成中,请稍后刷新...'))
|
|
: GridView.builder(
|
|
padding: const EdgeInsets.all(12),
|
|
gridDelegate:
|
|
const SliverGridDelegateWithFixedCrossAxisCount(
|
|
crossAxisCount: 2,
|
|
mainAxisSpacing: 12,
|
|
crossAxisSpacing: 12,
|
|
childAspectRatio: 0.8,
|
|
),
|
|
itemCount: _selected == null
|
|
? done.length
|
|
: done.where((i) => i.angle == _selected).length,
|
|
itemBuilder: (ctx, idx) {
|
|
final shown = _selected == null
|
|
? done
|
|
: done.where((i) => i.angle == _selected).toList();
|
|
final img = shown[idx];
|
|
return Card(
|
|
clipBehavior: Clip.antiAlias,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Expanded(
|
|
child: Image.network(
|
|
AppConfig.resolveUrl(img.url),
|
|
fit: BoxFit.cover,
|
|
errorBuilder: (_, _, _) => const Icon(
|
|
Icons.broken_image_outlined,
|
|
size: 48,
|
|
color: Colors.grey),
|
|
),
|
|
),
|
|
Padding(
|
|
padding: const EdgeInsets.all(8),
|
|
child: Text(_angleLabels[img.angle] ?? img.angle,
|
|
textAlign: TextAlign.center,
|
|
style: const TextStyle(
|
|
fontSize: 13,
|
|
fontWeight: FontWeight.bold)),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
// 信息流广告位:广告未开通(pangleAppId 为空)不渲染
|
|
if (ads.enabled) ads.showBanner(context),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|