feat(reward): 新增客户端奖励中心
This commit is contained in:
1 parent
67670d46b1
commit
bea08110c9
68 files changed
+3987
-332
No files matched your search
@@ -0,0 +1,242 @@
|
||||
// Author: fruit.com.cn
|
||||
|
||||
import 'json_numbers.dart';
|
||||
|
||||
/// 奖励中心首屏数据。
|
||||
class RewardOverview {
|
||||
const RewardOverview({
|
||||
required this.serverDate,
|
||||
required this.timezone,
|
||||
required this.coinBalance,
|
||||
required this.checkin,
|
||||
this.sections = const [],
|
||||
this.activities = const [],
|
||||
});
|
||||
|
||||
final String serverDate;
|
||||
final String timezone;
|
||||
final int coinBalance;
|
||||
final RewardCheckinState checkin;
|
||||
final List<RewardSection> sections;
|
||||
final List<RewardActivity> activities;
|
||||
|
||||
factory RewardOverview.fromJson(Map<String, dynamic> json) {
|
||||
return RewardOverview(
|
||||
serverDate: json['serverDate'] as String? ?? '',
|
||||
timezone: json['timezone'] as String? ?? '',
|
||||
coinBalance: jsonToInt(json['coinBalance']),
|
||||
checkin: RewardCheckinState.fromJson(_map(json['checkin'])),
|
||||
sections: _maps(json['sections']).map(RewardSection.fromJson).toList(),
|
||||
activities: _maps(
|
||||
json['activities'],
|
||||
).map(RewardActivity.fromJson).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 七日签到状态。
|
||||
class RewardCheckinState {
|
||||
const RewardCheckinState({
|
||||
required this.taskId,
|
||||
required this.checkedInToday,
|
||||
required this.streak,
|
||||
required this.currentDay,
|
||||
this.days = const [],
|
||||
});
|
||||
|
||||
final String taskId;
|
||||
final bool checkedInToday;
|
||||
final int streak;
|
||||
final int currentDay;
|
||||
final List<RewardCheckinDay> days;
|
||||
|
||||
factory RewardCheckinState.fromJson(Map<String, dynamic> json) {
|
||||
return RewardCheckinState(
|
||||
taskId: (json['taskId'] ?? '').toString(),
|
||||
checkedInToday: json['checkedInToday'] == true,
|
||||
streak: jsonToInt(json['streak']),
|
||||
currentDay: jsonToInt(json['currentDay']),
|
||||
days: _maps(json['days']).map(RewardCheckinDay.fromJson).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 签到周期中的一天。
|
||||
class RewardCheckinDay {
|
||||
const RewardCheckinDay({
|
||||
required this.dayIndex,
|
||||
required this.rewardCoin,
|
||||
required this.checked,
|
||||
required this.current,
|
||||
});
|
||||
|
||||
final int dayIndex;
|
||||
final int rewardCoin;
|
||||
final bool checked;
|
||||
final bool current;
|
||||
|
||||
factory RewardCheckinDay.fromJson(Map<String, dynamic> json) {
|
||||
return RewardCheckinDay(
|
||||
dayIndex: jsonToInt(json['dayIndex']),
|
||||
rewardCoin: jsonToInt(json['rewardCoin']),
|
||||
checked: json['checked'] == true,
|
||||
current: json['current'] == true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 一组奖励任务。
|
||||
class RewardSection {
|
||||
const RewardSection({
|
||||
required this.code,
|
||||
required this.title,
|
||||
this.tasks = const [],
|
||||
});
|
||||
|
||||
final String code;
|
||||
final String title;
|
||||
final List<RewardTask> tasks;
|
||||
|
||||
factory RewardSection.fromJson(Map<String, dynamic> json) {
|
||||
return RewardSection(
|
||||
code: json['code'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
tasks: _maps(json['tasks']).map(RewardTask.fromJson).toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 奖励任务卡片。
|
||||
class RewardTask {
|
||||
const RewardTask({
|
||||
required this.id,
|
||||
required this.code,
|
||||
required this.type,
|
||||
required this.title,
|
||||
required this.subtitle,
|
||||
required this.ctaText,
|
||||
required this.actionType,
|
||||
required this.actionUrl,
|
||||
required this.progressValue,
|
||||
required this.targetValue,
|
||||
required this.rewardCoin,
|
||||
required this.status,
|
||||
this.iconUrl = '',
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String code;
|
||||
final String type;
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final String ctaText;
|
||||
final String actionType;
|
||||
final String actionUrl;
|
||||
final String iconUrl;
|
||||
final int progressValue;
|
||||
final int targetValue;
|
||||
final int rewardCoin;
|
||||
final String status;
|
||||
|
||||
bool get claimable => status == 'COMPLETED';
|
||||
bool get claimed => status == 'CLAIMED';
|
||||
double get progress =>
|
||||
targetValue <= 0 ? 0 : (progressValue / targetValue).clamp(0.0, 1.0);
|
||||
|
||||
factory RewardTask.fromJson(Map<String, dynamic> json) {
|
||||
return RewardTask(
|
||||
id: (json['id'] ?? '').toString(),
|
||||
code: json['code'] as String? ?? '',
|
||||
type: json['type'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
subtitle: json['subtitle'] as String? ?? '',
|
||||
ctaText: json['ctaText'] as String? ?? '',
|
||||
actionType: json['actionType'] as String? ?? '',
|
||||
actionUrl: json['actionUrl'] as String? ?? '',
|
||||
iconUrl: json['iconUrl'] as String? ?? '',
|
||||
progressValue: jsonToInt(json['progressValue']),
|
||||
targetValue: jsonToInt(json['targetValue']),
|
||||
rewardCoin: jsonToInt(json['rewardCoin']),
|
||||
status: json['status'] as String? ?? 'IN_PROGRESS',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 奖励活动展示卡片。
|
||||
class RewardActivity {
|
||||
const RewardActivity({
|
||||
required this.id,
|
||||
required this.code,
|
||||
required this.title,
|
||||
required this.summary,
|
||||
required this.ctaText,
|
||||
required this.actionType,
|
||||
required this.actionUrl,
|
||||
this.coverUrl = '',
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String code;
|
||||
final String title;
|
||||
final String summary;
|
||||
final String ctaText;
|
||||
final String actionType;
|
||||
final String actionUrl;
|
||||
final String coverUrl;
|
||||
|
||||
factory RewardActivity.fromJson(Map<String, dynamic> json) {
|
||||
return RewardActivity(
|
||||
id: (json['id'] ?? '').toString(),
|
||||
code: json['code'] as String? ?? '',
|
||||
title: json['title'] as String? ?? '',
|
||||
summary: json['summary'] as String? ?? '',
|
||||
ctaText: json['ctaText'] as String? ?? '',
|
||||
actionType: json['actionType'] as String? ?? '',
|
||||
actionUrl: json['actionUrl'] as String? ?? '',
|
||||
coverUrl: json['coverUrl'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 签到或任务领取后的余额变化结果。
|
||||
class RewardActionResult {
|
||||
const RewardActionResult({
|
||||
required this.rewardCoin,
|
||||
required this.coinBalance,
|
||||
required this.alreadyCompleted,
|
||||
});
|
||||
|
||||
final int rewardCoin;
|
||||
final int coinBalance;
|
||||
final bool alreadyCompleted;
|
||||
|
||||
factory RewardActionResult.fromCheckin(Map<String, dynamic> json) {
|
||||
return RewardActionResult(
|
||||
rewardCoin: jsonToInt(json['rewardCoin']),
|
||||
coinBalance: jsonToInt(json['coinBalance']),
|
||||
alreadyCompleted: json['alreadyCheckedIn'] == true,
|
||||
);
|
||||
}
|
||||
|
||||
factory RewardActionResult.fromClaim(Map<String, dynamic> json) {
|
||||
return RewardActionResult(
|
||||
rewardCoin: jsonToInt(json['rewardCoin']),
|
||||
coinBalance: jsonToInt(json['coinBalance']),
|
||||
alreadyCompleted: json['alreadyGranted'] == true,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> _map(Object? value) {
|
||||
if (value is Map<String, dynamic>) return value;
|
||||
if (value is Map) return value.cast<String, dynamic>();
|
||||
return const {};
|
||||
}
|
||||
|
||||
List<Map<String, dynamic>> _maps(Object? value) {
|
||||
if (value is! List) return const [];
|
||||
return value
|
||||
.whereType<Map>()
|
||||
.map((item) => item.cast<String, dynamic>())
|
||||
.toList();
|
||||
}
|
||||
Reference in new issue
Block a user