Skip to content

Commit

Permalink
Add event fatigue tool page
Browse files Browse the repository at this point in the history
  • Loading branch information
narumi147 committed Jul 12, 2024
1 parent 6b303d0 commit 462223a
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 0 deletions.
167 changes: 167 additions & 0 deletions lib/app/modules/tools/event_fatigue.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import 'package:auto_size_text/auto_size_text.dart';

import 'package:chaldea/app/api/atlas.dart';
import 'package:chaldea/app/app.dart';
import 'package:chaldea/generated/l10n.dart';
import 'package:chaldea/models/gamedata/raw.dart';
import 'package:chaldea/models/models.dart';
import 'package:chaldea/utils/utils.dart';
import 'package:chaldea/widgets/region_based.dart';
import 'package:chaldea/widgets/widgets.dart';

class EventFatigueListPage extends StatefulWidget {
const EventFatigueListPage({super.key});

@override
State<EventFatigueListPage> createState() => _EventFatigueListPageState();
}

class _EventFatigueListPageState extends State<EventFatigueListPage>
with RegionBasedState<List<MstEventSvtFatigue>, EventFatigueListPage> {
List<MstEventSvtFatigue> get fatigues => data!;

@override
void initState() {
super.initState();
region = Region.jp;
doFetchData();
}

@override
Future<List<MstEventSvtFatigue>?> fetchData(Region? r, {Duration? expireAfter}) async {
return AtlasApi.mstData(
'mstEventSvtFatigue', (json) => (json as List).map((e) => MstEventSvtFatigue.fromJson(e)).toList(),
region: r ?? Region.jp, expireAfter: expireAfter);
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Fatigue Events"),
actions: [
dropdownRegion(),
// popupMenu,
],
),
body: buildBody(context),
);
}

@override
Widget buildContent(BuildContext context, List<MstEventSvtFatigue> fatigueList) {
final fatigues = <int, List<MstEventSvtFatigue>>{};
for (final fatigue in fatigueList) {
fatigues.putIfAbsent(fatigue.eventId, () => []).add(fatigue);
}
final eventIds = fatigues.keys.toList();
eventIds.sort2((e) => db.gameData.events[e]?.startedAt ?? e, reversed: true);
return ListView.builder(
padding: const EdgeInsets.symmetric(vertical: 8),
itemCount: eventIds.length,
itemBuilder: (context, index) {
final eventId = eventIds[index];
return ListTile(
title: Text(db.gameData.events[eventId]?.lName.l.setMaxLines(1) ?? 'Event $eventId'),
subtitle: Text('No.$eventId'),
trailing: Icon(DirectionalIcons.keyboard_arrow_forward(context)),
onTap: () {
router.pushPage(_EventSvtFatigueDetailPage(fatigues: fatigues[eventId]!, region: region ?? Region.jp));
},
);
},
);
}
}

class _EventSvtFatigueDetailPage extends StatelessWidget {
final List<MstEventSvtFatigue> fatigues;
final Region region;
const _EventSvtFatigueDetailPage({required this.fatigues, required this.region});

@override
Widget build(BuildContext context) {
// key: priority-duration-releaseId
final eventId = fatigues.first.eventId;
final groups = <(int, int, int), List<MstEventSvtFatigue>>{};
for (final fatigue in fatigues) {
groups.putIfAbsent((fatigue.priority, fatigue.fatigueTime, fatigue.commonReleaseId), () => []).add(fatigue);
}
final keys = groups.keys.toList();
keys.sortByList((e) => [-e.$1, e.$2, -e.$3]);
return Scaffold(
appBar: AppBar(
title: Text('Fatigues: ${db.gameData.events[eventId]?.lShortName.l.setMaxLines(1) ?? eventId}'),
actions: [
IconButton(
onPressed: () {
router.push(url: Routes.eventI(eventId));
},
icon: const Icon(Icons.flag),
),
],
),
body: ListView.builder(
itemBuilder: (context, index) {
final (priority, time, releaseId) = keys[index];
final group = groups[keys[index]]!..sort((a, b) => SvtFilterData.compareId(a.svtId, b.svtId));

List<Widget> children = [
ListTile(
dense: true,
title: Text('Fatigue Time: ${getDuration(time)}'),
trailing: releaseId == 0
? null
: TextButton(
onPressed: () {
router.push(url: Routes.commonReleaseI(releaseId));
},
child: Text('${S.current.condition} $releaseId'),
),
),
const Divider(indent: 16, endIndent: 16),
if (group.any((e) => e.svtId == 0))
ListTile(
title: Text('${S.current.general_all} ${S.current.servant}'),
),
];
group.removeWhere((e) => e.svtId == 0);
if (group.isNotEmpty) {
children.add(GridView.extent(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
maxCrossAxisExtent: 48,
childAspectRatio: 132 / 144,
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
children: group.map((fatigue) {
return db.gameData.servantsById[fatigue.svtId]?.iconBuilder(context: context) ??
AutoSizeText('${fatigue.svtId}');
}).toList(),
));
}

return TileGroup(
header: '${S.current.priority} $priority',
children: [
...children,
],
);
},
itemCount: keys.length,
),
);
}

String getDuration(int t) {
final duration = Duration(seconds: t);
final hours = duration.inHours, minutes = duration.inMinutes % 60, seconds = duration.inSeconds % 60;
String timeText = '${hours}h';
if (minutes != 0 || seconds != 0) {
timeText += '${minutes}m';
if (seconds != 0) {
timeText += '${seconds}s';
}
}
return timeText;
}
}
2 changes: 2 additions & 0 deletions lib/app/modules/tools/tool_list_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import 'bond_table.dart';
import 'chara_figure_marker.dart';
import 'combine_image_page.dart';
import 'custom_chara_figure.dart';
import 'event_fatigue.dart';
import 'realtime_svt_filter.dart';

class ToolListPage extends StatelessWidget {
Expand Down Expand Up @@ -44,6 +45,7 @@ class ToolListPage extends StatelessWidget {
buildOne('Master Level', const MasterExpPage()),
buildOne('${S.current.bond} (${S.current.total})', const BondTotalTable()),
buildOne('Event Servant Filter', const RealtimeSvtFilterPage()),
buildOne('Event Fatigues', const EventFatigueListPage()),
],
),
TileGroup(
Expand Down
16 changes: 16 additions & 0 deletions lib/generated/models/gamedata/raw.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 27 additions & 0 deletions lib/models/gamedata/raw.dart
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,30 @@ class MstSvtFilter {
factory MstSvtFilter.fromJson(Map<dynamic, dynamic> json) => _$MstSvtFilterFromJson(json);
Map<String, dynamic> toJson() => _$MstSvtFilterToJson(this);
}
// {
// "eventId": 80273,
// "svtId": 401400,
// "priority": 0,
// "fatigueTime": 18000,
// "commonReleaseId": 0
// }

@JsonSerializable()
class MstEventSvtFatigue {
int eventId;
int svtId;
int priority;
int fatigueTime;
int commonReleaseId;

MstEventSvtFatigue({
required this.eventId,
this.svtId = 0,
this.priority = 0,
this.fatigueTime = 0,
this.commonReleaseId = 0,
});

factory MstEventSvtFatigue.fromJson(Map<dynamic, dynamic> json) => _$MstEventSvtFatigueFromJson(json);
Map<String, dynamic> toJson() => _$MstEventSvtFatigueToJson(this);
}
6 changes: 6 additions & 0 deletions lib/models/userdata/filter_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,12 @@ class SvtFilterData with FilterDataMixin {

Map<String, dynamic> toJson() => _$SvtFilterDataToJson(this);

static int compareId(int a, int b, {List<SvtCompare>? keys, List<bool>? reversed, User? user}) {
final aa = db.gameData.servantsById[a], bb = db.gameData.servantsById[b];
if (aa == null && bb == null) return a.compareTo(b);
return compare(aa, bb, keys: keys, reversed: reversed, user: user);
}

static int compare(Servant? a, Servant? b, {List<SvtCompare>? keys, List<bool>? reversed, User? user}) {
if (a == null && b == null) return 0;
if (a == null) return -1;
Expand Down

0 comments on commit 462223a

Please sign in to comment.