789 lines
22 KiB
Dart
789 lines
22 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:yumi/app/constants/sc_global_config.dart';
|
|
import 'package:yumi/app/routes/sc_fluro_navigator.dart';
|
|
import 'package:yumi/app_localizations.dart';
|
|
import 'package:yumi/modules/index/main_route.dart';
|
|
import 'package:yumi/shared/business_logic/models/res/sc_task_list_res.dart';
|
|
import 'package:yumi/shared/data_sources/sources/repositories/sc_user_repository_impl.dart';
|
|
|
|
class TaskPage extends StatefulWidget {
|
|
const TaskPage({super.key});
|
|
|
|
@override
|
|
State<TaskPage> createState() => _TaskPageState();
|
|
}
|
|
|
|
class _TaskPageState extends State<TaskPage> {
|
|
static const String _taskMicAsset = 'sc_images/index/sc_icon_task_mic.png';
|
|
static const String _taskGameAsset = 'sc_images/index/sc_icon_task_game.png';
|
|
static const String _taskGiftAsset = 'sc_images/index/sc_icon_task_gift.png';
|
|
|
|
final SCAccountRepository _repository = SCAccountRepository();
|
|
final Set<num> _claimedTaskIds = {};
|
|
final Set<num> _claimingTaskIds = {};
|
|
List<SCTaskListRes> _tasks = [];
|
|
bool _loading = true;
|
|
String? _toastMessage;
|
|
Timer? _toastTimer;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_loadTasks();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_toastTimer?.cancel();
|
|
super.dispose();
|
|
}
|
|
|
|
Future<void> _loadTasks() async {
|
|
try {
|
|
final tasks = await _repository.tasks();
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_tasks =
|
|
tasks
|
|
..sort((a, b) => (a.sortOrder ?? 0).compareTo(b.sortOrder ?? 0));
|
|
_loading = false;
|
|
});
|
|
} catch (_) {
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_tasks = [];
|
|
_loading = false;
|
|
});
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final dailyTasks = _sectionTasks(isNewcomer: false);
|
|
final newcomerTasks = _sectionTasks(isNewcomer: true);
|
|
|
|
return Scaffold(
|
|
backgroundColor: const Color(0xFF00221D),
|
|
body: SafeArea(
|
|
bottom: false,
|
|
child: Stack(
|
|
children: [
|
|
Column(
|
|
children: [
|
|
_buildTopBar(),
|
|
Expanded(
|
|
child: RefreshIndicator(
|
|
color: const Color(0xFF16DBB2),
|
|
backgroundColor: const Color(0xFF06342A),
|
|
onRefresh: _loadTasks,
|
|
child: SingleChildScrollView(
|
|
physics: const AlwaysScrollableScrollPhysics(
|
|
parent: BouncingScrollPhysics(),
|
|
),
|
|
padding: EdgeInsets.fromLTRB(10.w, 18.w, 10.w, 28.w),
|
|
child: Column(
|
|
children: [
|
|
if (_loading)
|
|
Padding(
|
|
padding: EdgeInsets.only(top: 120.w),
|
|
child: SizedBox(
|
|
width: 24.w,
|
|
height: 24.w,
|
|
child: const CircularProgressIndicator(
|
|
strokeWidth: 2,
|
|
color: Color(0xFF16DBB2),
|
|
),
|
|
),
|
|
)
|
|
else
|
|
..._buildTaskSections(dailyTasks, newcomerTasks),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
if (_toastMessage != null) _buildToast(),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildTopBar() {
|
|
return SizedBox(
|
|
height: 44.w,
|
|
child: Stack(
|
|
alignment: Alignment.center,
|
|
children: [
|
|
Align(
|
|
alignment: AlignmentDirectional.centerStart,
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () => SCNavigatorUtils.goBack(context),
|
|
child: SizedBox(
|
|
width: 44.w,
|
|
height: 44.w,
|
|
child: Icon(
|
|
SCGlobalConfig.lang == 'ar'
|
|
? Icons.keyboard_arrow_right
|
|
: Icons.keyboard_arrow_left,
|
|
color: Colors.white,
|
|
size: 28.w,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Text(
|
|
SCAppLocalizations.of(context)!.task,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 20.sp,
|
|
fontWeight: FontWeight.w500,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget _buildToast() {
|
|
return Positioned(
|
|
left: 50.w,
|
|
right: 50.w,
|
|
top: 316.w,
|
|
child: IgnorePointer(
|
|
child: Container(
|
|
height: 56.w,
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF063F36),
|
|
borderRadius: BorderRadius.circular(12.w),
|
|
border: Border.all(color: const Color(0xFF18DDB5), width: 1.w),
|
|
),
|
|
child: Text(
|
|
_toastMessage!,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 13.sp,
|
|
fontWeight: FontWeight.w400,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
List<Widget> _buildTaskSections(
|
|
List<_TaskUiItem> dailyTasks,
|
|
List<_TaskUiItem> newcomerTasks,
|
|
) {
|
|
final sections = <Widget>[];
|
|
final l10n = SCAppLocalizations.of(context)!;
|
|
if (dailyTasks.isNotEmpty) {
|
|
sections.add(
|
|
_TaskSection(
|
|
title: l10n.dailyTasks,
|
|
subtitle: l10n.resetsDailyAtMidnight,
|
|
tasks: dailyTasks,
|
|
onAction: _handleTaskAction,
|
|
isClaiming: _claimingTaskIds.contains,
|
|
),
|
|
);
|
|
}
|
|
if (newcomerTasks.isNotEmpty) {
|
|
if (sections.isNotEmpty) sections.add(SizedBox(height: 14.w));
|
|
sections.add(
|
|
_TaskSection(
|
|
title: l10n.exclusiveForNewcomers,
|
|
subtitle: l10n.limitedToOneTime,
|
|
tasks: newcomerTasks,
|
|
onAction: _handleTaskAction,
|
|
isClaiming: _claimingTaskIds.contains,
|
|
),
|
|
);
|
|
}
|
|
return sections;
|
|
}
|
|
|
|
List<_TaskUiItem> _sectionTasks({required bool isNewcomer}) {
|
|
final source =
|
|
_tasks.where((task) {
|
|
final taskType = (task.taskType ?? 0).toInt();
|
|
return isNewcomer ? taskType != 0 : taskType == 0;
|
|
}).toList();
|
|
final mapped = source.map(_mapTask).toList();
|
|
if (_tasks.isNotEmpty) return mapped;
|
|
final demoTasks = _demoTasks(isNewcomer: isNewcomer);
|
|
return demoTasks
|
|
.map(
|
|
(task) =>
|
|
_claimedTaskIds.contains(task.id)
|
|
? task.copyWith(status: _TaskActionStatus.claimed)
|
|
: task,
|
|
)
|
|
.toList();
|
|
}
|
|
|
|
_TaskUiItem _mapTask(SCTaskListRes task) {
|
|
final id = task.taskId ?? -1;
|
|
final currentValue = _parseNumber(task.completedValue) ?? 0;
|
|
final targetValue =
|
|
_parseNumber(task.targetValue) ??
|
|
_parseNumber(task.conditionValue) ??
|
|
1000000;
|
|
final claimed =
|
|
_claimedTaskIds.contains(id) || (task.isRewardCollected ?? 0) == 1;
|
|
final completedByValue = targetValue > 0 && currentValue >= targetValue;
|
|
final completedByStatus = (task.taskStatus ?? 0) == 1;
|
|
final status =
|
|
claimed
|
|
? _TaskActionStatus.claimed
|
|
: (completedByStatus || completedByValue)
|
|
? _TaskActionStatus.claim
|
|
: _TaskActionStatus.go;
|
|
|
|
return _TaskUiItem(
|
|
id: id,
|
|
title:
|
|
_nonEmpty(task.taskName) ??
|
|
SCAppLocalizations.of(context)!.useMicrophoneForOneMin,
|
|
progressText:
|
|
'${_formatPlainNumber(currentValue)}/${_formatPlainNumber(targetValue)}',
|
|
rewardText: _formatCompactNumber(task.quantity ?? 1100),
|
|
status: status,
|
|
iconAsset: _iconForTask(task),
|
|
jumpPage: _nonEmpty(task.jumpPage),
|
|
fromApi: task.taskId != null,
|
|
);
|
|
}
|
|
|
|
Future<void> _handleTaskAction(_TaskUiItem task) async {
|
|
if (task.status == _TaskActionStatus.claimed) return;
|
|
if (task.status == _TaskActionStatus.go) {
|
|
_openJumpPage(task.jumpPage);
|
|
return;
|
|
}
|
|
|
|
if (_claimingTaskIds.contains(task.id)) return;
|
|
setState(() => _claimingTaskIds.add(task.id));
|
|
var success = true;
|
|
if (task.fromApi && task.id >= 0) {
|
|
try {
|
|
success = await _repository.taskReward(task.id);
|
|
} catch (_) {
|
|
success = false;
|
|
}
|
|
}
|
|
if (!mounted) return;
|
|
setState(() {
|
|
_claimingTaskIds.remove(task.id);
|
|
if (success) _claimedTaskIds.add(task.id);
|
|
});
|
|
if (success) {
|
|
_showToast(SCAppLocalizations.of(context)!.rewardClaimedSuccessfully);
|
|
unawaited(_loadTasks());
|
|
} else {
|
|
_showToast(SCAppLocalizations.of(context)!.rewardClaimFailed);
|
|
}
|
|
}
|
|
|
|
void _openJumpPage(String? jumpPage) {
|
|
final target = jumpPage?.trim() ?? '';
|
|
if (target.isEmpty) return;
|
|
if (target.startsWith('http://') || target.startsWith('https://')) {
|
|
SCNavigatorUtils.push(
|
|
context,
|
|
'${SCMainRoute.webViewPage}?url=${Uri.encodeComponent(target)}&showTitle=false',
|
|
);
|
|
return;
|
|
}
|
|
if (target.startsWith('/')) {
|
|
SCNavigatorUtils.push(context, target);
|
|
}
|
|
}
|
|
|
|
void _showToast(String message) {
|
|
_toastTimer?.cancel();
|
|
setState(() => _toastMessage = message);
|
|
_toastTimer = Timer(const Duration(milliseconds: 1600), () {
|
|
if (mounted) setState(() => _toastMessage = null);
|
|
});
|
|
}
|
|
|
|
String _iconForTask(SCTaskListRes task) {
|
|
final text =
|
|
'${task.conditionType ?? ''} ${task.taskName ?? ''} ${task.taskDesc ?? ''}'
|
|
.toLowerCase();
|
|
if (text.contains('gift')) return _taskGiftAsset;
|
|
if (text.contains('game')) return _taskGameAsset;
|
|
return _taskMicAsset;
|
|
}
|
|
|
|
static num? _parseNumber(Object? value) {
|
|
if (value is num) return value;
|
|
if (value is String) return num.tryParse(value);
|
|
return null;
|
|
}
|
|
|
|
static String? _nonEmpty(String? value) {
|
|
final text = value?.trim();
|
|
return text == null || text.isEmpty ? null : text;
|
|
}
|
|
|
|
static String _formatPlainNumber(num value) {
|
|
if (value % 1 == 0) return value.toInt().toString();
|
|
return value.toStringAsFixed(1);
|
|
}
|
|
|
|
static String _formatCompactNumber(num value) {
|
|
final absValue = value.abs();
|
|
if (absValue >= 1000000) {
|
|
return '${_trimTrailingZero(value / 1000000)}m';
|
|
}
|
|
if (absValue >= 1000) {
|
|
return '${_trimTrailingZero(value / 1000)}k';
|
|
}
|
|
return _formatPlainNumber(value);
|
|
}
|
|
|
|
static String _trimTrailingZero(num value) {
|
|
final text = value.toStringAsFixed(1);
|
|
return text.endsWith('.0') ? text.substring(0, text.length - 2) : text;
|
|
}
|
|
|
|
List<_TaskUiItem> _demoTasks({required bool isNewcomer}) {
|
|
final title = SCAppLocalizations.of(context)!.useMicrophoneForOneMin;
|
|
final baseId = isNewcomer ? -200 : -100;
|
|
return [
|
|
_TaskUiItem(
|
|
id: baseId - 1,
|
|
title: title,
|
|
progressText: '0/1000000',
|
|
rewardText: '1.1k',
|
|
status: _TaskActionStatus.go,
|
|
iconAsset: _taskMicAsset,
|
|
),
|
|
_TaskUiItem(
|
|
id: baseId - 2,
|
|
title: title,
|
|
progressText: '0/1000000',
|
|
rewardText: '1.1k',
|
|
status: _TaskActionStatus.claim,
|
|
iconAsset: _taskGameAsset,
|
|
),
|
|
_TaskUiItem(
|
|
id: baseId - 3,
|
|
title: title,
|
|
progressText: '0/1000000',
|
|
rewardText: '1.1k',
|
|
status: _TaskActionStatus.claimed,
|
|
iconAsset: _taskGiftAsset,
|
|
),
|
|
];
|
|
}
|
|
}
|
|
|
|
class _TaskSection extends StatelessWidget {
|
|
const _TaskSection({
|
|
required this.title,
|
|
required this.subtitle,
|
|
required this.tasks,
|
|
required this.onAction,
|
|
required this.isClaiming,
|
|
});
|
|
|
|
final String title;
|
|
final String subtitle;
|
|
final List<_TaskUiItem> tasks;
|
|
final ValueChanged<_TaskUiItem> onAction;
|
|
final bool Function(num id) isClaiming;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Container(
|
|
width: double.infinity,
|
|
decoration: BoxDecoration(
|
|
color: const Color(0xFF052E25),
|
|
borderRadius: BorderRadius.circular(7.w),
|
|
border: Border.all(color: const Color(0xFFB4FCCE), width: 1.w),
|
|
),
|
|
child: Column(
|
|
children: [
|
|
Padding(
|
|
padding: EdgeInsets.fromLTRB(12.w, 24.w, 12.w, 12.w),
|
|
child: Row(
|
|
children: [
|
|
Expanded(child: _GradientTaskTitle(title)),
|
|
SizedBox(width: 8.w),
|
|
Text(
|
|
subtitle,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
for (int i = 0; i < tasks.length; i++) ...[
|
|
_TaskRow(
|
|
task: tasks[i],
|
|
onAction: onAction,
|
|
claiming: isClaiming(tasks[i].id),
|
|
),
|
|
if (i != tasks.length - 1)
|
|
Padding(
|
|
padding: EdgeInsetsDirectional.only(start: 62.w),
|
|
child: Divider(
|
|
height: 1.w,
|
|
thickness: 0.5.w,
|
|
color: const Color(0xFF295346).withValues(alpha: 0.8),
|
|
),
|
|
),
|
|
],
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _GradientTaskTitle extends StatelessWidget {
|
|
const _GradientTaskTitle(this.text);
|
|
|
|
final String text;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final style = TextStyle(
|
|
fontSize: 16.sp,
|
|
fontWeight: FontWeight.w900,
|
|
height: 1,
|
|
);
|
|
|
|
return LayoutBuilder(
|
|
builder: (context, constraints) {
|
|
return SizedBox(
|
|
width: constraints.maxWidth,
|
|
height: 23.w,
|
|
child: Stack(
|
|
clipBehavior: Clip.none,
|
|
children: [
|
|
PositionedDirectional(
|
|
top: 3.w,
|
|
start: 0,
|
|
end: 0,
|
|
child: Text(
|
|
text,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: style.copyWith(color: const Color(0xFF157D10)),
|
|
),
|
|
),
|
|
PositionedDirectional(
|
|
start: 0,
|
|
end: 0,
|
|
child: Text(
|
|
text,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: style.copyWith(
|
|
foreground:
|
|
Paint()
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 1.w
|
|
..color = const Color(0xFF157D10),
|
|
),
|
|
),
|
|
),
|
|
PositionedDirectional(
|
|
start: 0,
|
|
end: 0,
|
|
child: ShaderMask(
|
|
blendMode: BlendMode.srcIn,
|
|
shaderCallback:
|
|
(bounds) => const LinearGradient(
|
|
begin: Alignment.centerRight,
|
|
end: Alignment.centerLeft,
|
|
colors: [
|
|
Color(0xFFFFFFFF),
|
|
Color(0xFFBEFAE8),
|
|
Color(0xFFFFFFFF),
|
|
],
|
|
stops: [0.224, 0.4907, 0.7224],
|
|
).createShader(bounds),
|
|
child: Text(
|
|
text,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: style.copyWith(color: Colors.white),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TaskRow extends StatelessWidget {
|
|
const _TaskRow({
|
|
required this.task,
|
|
required this.onAction,
|
|
required this.claiming,
|
|
});
|
|
|
|
final _TaskUiItem task;
|
|
final ValueChanged<_TaskUiItem> onAction;
|
|
final bool claiming;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return SizedBox(
|
|
height: 65.w,
|
|
child: Row(
|
|
children: [
|
|
SizedBox(width: 12.w),
|
|
Container(
|
|
width: 42.w,
|
|
height: 42.w,
|
|
decoration: const BoxDecoration(
|
|
color: Color(0x30BEF9E8),
|
|
shape: BoxShape.circle,
|
|
),
|
|
alignment: Alignment.center,
|
|
child: Image.asset(
|
|
task.iconAsset,
|
|
width: 29.4.w,
|
|
height: 29.4.w,
|
|
fit: BoxFit.contain,
|
|
),
|
|
),
|
|
SizedBox(width: 20.w),
|
|
Expanded(
|
|
child: Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
Text(
|
|
task.title,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: Colors.white,
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1.15,
|
|
),
|
|
),
|
|
SizedBox(height: 3.w),
|
|
Text(
|
|
task.progressText,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: Colors.white.withValues(alpha: 0.62),
|
|
fontSize: 10.sp,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1,
|
|
),
|
|
),
|
|
SizedBox(height: 6.w),
|
|
Row(
|
|
children: [
|
|
Image.asset(
|
|
'sc_images/general/sc_icon_jb.png',
|
|
width: 12.w,
|
|
height: 12.w,
|
|
),
|
|
SizedBox(width: 5.w),
|
|
Text(
|
|
task.rewardText,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: const Color(0xFFFFD155),
|
|
fontSize: 12.sp,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
SizedBox(width: 10.w),
|
|
_TaskActionButton(
|
|
status: task.status,
|
|
claiming: claiming,
|
|
onTap: () => onAction(task),
|
|
),
|
|
SizedBox(width: 12.w),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TaskActionButton extends StatelessWidget {
|
|
const _TaskActionButton({
|
|
required this.status,
|
|
required this.claiming,
|
|
required this.onTap,
|
|
});
|
|
|
|
final _TaskActionStatus status;
|
|
final bool claiming;
|
|
final VoidCallback onTap;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final config = _TaskButtonConfig.fromStatus(
|
|
status,
|
|
SCAppLocalizations.of(context)!,
|
|
);
|
|
return GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: claiming ? null : onTap,
|
|
child: Container(
|
|
width: config.width.w,
|
|
height: 20.w,
|
|
alignment: Alignment.center,
|
|
decoration: BoxDecoration(
|
|
borderRadius: BorderRadius.circular(10.w),
|
|
border:
|
|
config.borderColor == null
|
|
? null
|
|
: Border.all(color: config.borderColor!, width: 1.w),
|
|
gradient: config.gradient,
|
|
color: config.gradient == null ? config.backgroundColor : null,
|
|
),
|
|
child:
|
|
claiming
|
|
? SizedBox(
|
|
width: 10.w,
|
|
height: 10.w,
|
|
child: CircularProgressIndicator(
|
|
strokeWidth: 1.5.w,
|
|
color: config.textColor,
|
|
),
|
|
)
|
|
: Text(
|
|
config.label,
|
|
maxLines: 1,
|
|
overflow: TextOverflow.ellipsis,
|
|
style: TextStyle(
|
|
color: config.textColor,
|
|
fontSize: 13.sp,
|
|
fontWeight: FontWeight.w400,
|
|
height: 1,
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class _TaskButtonConfig {
|
|
const _TaskButtonConfig({
|
|
required this.label,
|
|
required this.textColor,
|
|
required this.width,
|
|
this.backgroundColor,
|
|
this.borderColor,
|
|
this.gradient,
|
|
});
|
|
|
|
final String label;
|
|
final Color textColor;
|
|
final double width;
|
|
final Color? backgroundColor;
|
|
final Color? borderColor;
|
|
final Gradient? gradient;
|
|
|
|
factory _TaskButtonConfig.fromStatus(
|
|
_TaskActionStatus status,
|
|
SCAppLocalizations l10n,
|
|
) {
|
|
switch (status) {
|
|
case _TaskActionStatus.claim:
|
|
return _TaskButtonConfig(
|
|
label: l10n.claim,
|
|
textColor: Color(0xFF2B1500),
|
|
width: 53,
|
|
gradient: const LinearGradient(
|
|
begin: Alignment.topCenter,
|
|
end: Alignment.bottomCenter,
|
|
colors: [Color(0xFFFFD981), Color(0xFFFF9E2D)],
|
|
),
|
|
);
|
|
case _TaskActionStatus.claimed:
|
|
return _TaskButtonConfig(
|
|
label: l10n.claimed,
|
|
textColor: Colors.white,
|
|
width: 58,
|
|
backgroundColor: const Color(0xFF062E28),
|
|
borderColor: Colors.white.withValues(alpha: 0.56),
|
|
);
|
|
case _TaskActionStatus.go:
|
|
return _TaskButtonConfig(
|
|
label: l10n.go,
|
|
textColor: Colors.white,
|
|
width: 53,
|
|
backgroundColor: const Color(0xFF062E28),
|
|
borderColor: const Color(0xFF98E4C2),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
class _TaskUiItem {
|
|
const _TaskUiItem({
|
|
required this.id,
|
|
required this.title,
|
|
required this.progressText,
|
|
required this.rewardText,
|
|
required this.status,
|
|
required this.iconAsset,
|
|
this.jumpPage,
|
|
this.fromApi = false,
|
|
});
|
|
|
|
final num id;
|
|
final String title;
|
|
final String progressText;
|
|
final String rewardText;
|
|
final _TaskActionStatus status;
|
|
final String iconAsset;
|
|
final String? jumpPage;
|
|
final bool fromApi;
|
|
|
|
_TaskUiItem copyWith({_TaskActionStatus? status}) {
|
|
return _TaskUiItem(
|
|
id: id,
|
|
title: title,
|
|
progressText: progressText,
|
|
rewardText: rewardText,
|
|
status: status ?? this.status,
|
|
iconAsset: iconAsset,
|
|
jumpPage: jumpPage,
|
|
fromApi: fromApi,
|
|
);
|
|
}
|
|
}
|
|
|
|
enum _TaskActionStatus { go, claim, claimed }
|