184 lines
5.8 KiB
Dart
184 lines
5.8 KiB
Dart
import 'package:client_proxy_framework/client_proxy_framework.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:google_fonts/google_fonts.dart';
|
|
|
|
import '../../core/app_env.dart';
|
|
import '../../core/user/user_state.dart';
|
|
import '../../design/pencil_theme.dart';
|
|
import '../../widgets/pencil_chrome.dart';
|
|
import '../../widgets/pencil_yellow_white_background.dart';
|
|
import '../generate/generate_result_screen.dart';
|
|
|
|
/// 从 My History 点「生成中」任务进入:轮询 [ImageApi.getProgress],完成后进入 [GenerateResultScreen]。
|
|
///
|
|
/// 与 app_client [GenerateProgressScreen] 行为对齐(权威数据源为 `/v1/image/progress`)。
|
|
class HistoryTaskProgressScreen extends StatefulWidget {
|
|
const HistoryTaskProgressScreen({super.key, required this.taskId});
|
|
|
|
final String taskId;
|
|
|
|
@override
|
|
State<HistoryTaskProgressScreen> createState() =>
|
|
_HistoryTaskProgressScreenState();
|
|
}
|
|
|
|
class _HistoryTaskProgressScreenState extends State<HistoryTaskProgressScreen> {
|
|
ImageProgressPollHandle? _pollHandle;
|
|
String _genStatus = '';
|
|
int _genProgress = 0;
|
|
String? _genResultUrl;
|
|
String? _genError;
|
|
bool _navigated = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_startPoll();
|
|
}
|
|
|
|
void _startPoll() {
|
|
_pollHandle?.cancel();
|
|
_pollHandle = ImageProgressPoll.start(
|
|
app: currentBackendAppType(),
|
|
taskId: widget.taskId,
|
|
userId: UserState.userId.value,
|
|
interval: const Duration(seconds: 5),
|
|
onTick: _onTick,
|
|
onFatalError: (msg) {
|
|
if (!mounted || _navigated) return;
|
|
setState(() => _genError = msg);
|
|
},
|
|
);
|
|
}
|
|
|
|
void _onTick(ProgressPollTick tick) {
|
|
if (!mounted || _navigated) return;
|
|
final res = tick.response;
|
|
if (!res.isSuccess || res.data == null) {
|
|
setState(() => _genError = res.msg.isNotEmpty ? res.msg : 'Progress error');
|
|
return;
|
|
}
|
|
final p = res.data!;
|
|
setState(() {
|
|
_genError = null;
|
|
_genStatus = p.status ?? '';
|
|
_genProgress = p.progress ?? 0;
|
|
_genResultUrl = p.resultUrl;
|
|
});
|
|
|
|
if (ProgressPollSemantics.isProgressSuccess(p)) {
|
|
_navigated = true;
|
|
_pollHandle?.cancel();
|
|
_pollHandle = null;
|
|
final url = _genResultUrl ?? '';
|
|
Navigator.of(context).pushReplacement(
|
|
MaterialPageRoute<void>(
|
|
builder: (_) => GenerateResultScreen(
|
|
taskId: widget.taskId,
|
|
resultUrl: url,
|
|
),
|
|
),
|
|
);
|
|
return;
|
|
}
|
|
|
|
if (ProgressPollSemantics.isProgressFailure(p)) {
|
|
_pollHandle?.cancel();
|
|
_pollHandle = null;
|
|
setState(() {
|
|
_genError ??= 'Task failed (${p.status})';
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_pollHandle?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return PencilYellowWhitePageBackground(
|
|
child: Scaffold(
|
|
backgroundColor: Colors.transparent,
|
|
body: SafeArea(
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Padding(
|
|
padding: const EdgeInsets.fromLTRB(2, 0, 14, 8),
|
|
child: SizedBox(
|
|
height: 56,
|
|
child: Row(
|
|
children: [
|
|
PencilRoundBackButton(
|
|
onPressed: () => Navigator.of(context).pop(),
|
|
),
|
|
Expanded(
|
|
child: Center(
|
|
child: Text(
|
|
'Generating',
|
|
style: GoogleFonts.inter(
|
|
fontSize: 19,
|
|
fontWeight: FontWeight.w700,
|
|
fontStyle: FontStyle.italic,
|
|
color: PencilTheme.stone900,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(width: 44),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
Expanded(
|
|
child: Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 24),
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
if (_genError != null) ...[
|
|
Text(
|
|
_genError!,
|
|
style: GoogleFonts.inter(color: Colors.red),
|
|
textAlign: TextAlign.center,
|
|
),
|
|
] else ...[
|
|
LinearProgressIndicator(
|
|
value: _genProgress > 0 ? _genProgress / 100 : null,
|
|
color: PencilTheme.underlineGold,
|
|
),
|
|
const SizedBox(height: 16),
|
|
Text(
|
|
_genStatus.isEmpty ? 'Processing…' : _genStatus,
|
|
textAlign: TextAlign.center,
|
|
style: GoogleFonts.inter(
|
|
fontSize: 14,
|
|
color: PencilTheme.stone600,
|
|
),
|
|
),
|
|
Text(
|
|
'$_genProgress%',
|
|
textAlign: TextAlign.center,
|
|
style: GoogleFonts.inter(
|
|
fontSize: 28,
|
|
fontWeight: FontWeight.w700,
|
|
color: PencilTheme.stone900,
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|