Skip to content

Commit e4493b1

Browse files
committed
✨: implement questlist feature with state management and UI integration
1 parent 6100756 commit e4493b1

File tree

12 files changed

+167
-11
lines changed

12 files changed

+167
-11
lines changed

lib/components/kancolle_model/kancolle_parse.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ void kancolleMessageHandle(BuildContext context, WebMessage message) {
3434
case 'api_get_member':
3535
switch (seg[2]) {
3636
case 'questlist':
37-
37+
context.read<QuestlistCubit>().parse(result);
3838
case 'require_info':
3939
//TODO
4040
break;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import 'package:freezed_annotation/freezed_annotation.dart';
2+
3+
// 状態 1=未受領, 2=遂行中, 3=達成
4+
enum QuestState {
5+
@JsonValue(1)
6+
unaccepted,
7+
@JsonValue(2)
8+
ongoing,
9+
@JsonValue(3)
10+
achieved,
11+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,19 @@
1+
import 'dart:convert';
2+
13
import 'package:bloc/bloc.dart';
24
import 'package:freezed_annotation/freezed_annotation.dart';
5+
import 'package:equatable/equatable.dart';
36

47
part 'questlist_state.dart';
58
part 'questlist_cubit.freezed.dart';
69
part 'questlist_cubit.g.dart';
710

811
class QuestlistCubit extends Cubit<QuestlistState> {
912
QuestlistCubit() : super(QuestlistState.initial());
13+
14+
void parse(String jsonData) {
15+
final data = jsonDecode(jsonData);
16+
data['api_data']['questlist_type'] = 'loaded';
17+
emit(QuestlistState.fromJson(data['api_data']));
18+
}
1019
}

lib/components/kancolle_model/kcsapi/get/member/questlist/questlist_state.dart

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,21 @@
11
part of 'questlist_cubit.dart';
22

3-
@freezed
4-
class QuestlistState with _$QuestlistState {
3+
enum QuestState {
4+
@JsonValue(1)
5+
unaccepted,
6+
@JsonValue(2)
7+
ongoing,
8+
@JsonValue(3)
9+
achieved,
10+
}
11+
12+
@Freezed(unionKey: 'questlist_type', unionValueCase: FreezedUnionCase.pascal)
13+
class QuestlistState with _$QuestlistState implements EquatableMixin{
14+
const QuestlistState._();
515
const factory QuestlistState.initial() = _Initial;
616

17+
@JsonSerializable(fieldRename: FieldRename.snake)
18+
@FreezedUnionValue('loaded')
719
const factory QuestlistState.loaded({
820
required int apiCount,
921
required int apiCompletedKind,
@@ -15,6 +27,12 @@ class QuestlistState with _$QuestlistState {
1527

1628
factory QuestlistState.fromJson(Map<String, dynamic> json) =>
1729
_$QuestlistStateFromJson(json);
30+
31+
@override
32+
List<Object?> get props => [if(this is _Loaded) (this as _Loaded)];
33+
34+
@override
35+
bool? get stringify => true;
1836
}
1937

2038
@freezed
@@ -24,7 +42,7 @@ class Quest with _$Quest {
2442
@JsonKey(name: 'api_category') required int apiCategory,
2543
@JsonKey(name: 'api_type') required int apiType,
2644
@JsonKey(name: 'api_label_type') required int apiLabelType,
27-
@JsonKey(name: 'api_state') required int apiState,
45+
@JsonKey(name: 'api_state') required QuestState apiState,
2846
@JsonKey(name: 'api_title') required String apiTitle,
2947
@JsonKey(name: 'api_detail') required String apiDetail,
3048
@JsonKey(name: 'api_voice_id') required int apiVoicedId,
@@ -46,5 +64,6 @@ class ApiClist with _$ApiClist {
4664
@JsonKey(name: "api_c_flag") required int apiPage,
4765
}) = _ApiClist;
4866

49-
factory ApiClist.fromJson(Map<String, dynamic> json) => _$ApiClistFromJson(json);
50-
}
67+
factory ApiClist.fromJson(Map<String, dynamic> json) =>
68+
_$ApiClistFromJson(json);
69+
}

lib/constant.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,8 @@ class DockingView {
2323
static DockingItem createFFC() => DockingItem(name: 'fcc', weight: 0.2, widget: FleetForcesCommand());
2424

2525
static DockingItem createDryDock() => DockingItem(name: 'drydock', weight: 0.2, widget: Drydock());
26+
27+
static DockingItem createFleet(int id) => DockingItem(name: 'fleet$id', weight: 0.2, widget: FleetFormation(id: id));
28+
29+
static DockingItem createQuestlist() => DockingItem(name: 'questlist', weight: 0.2, widget: QuestlistView());
2630
}

lib/main.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class App extends StatelessWidget {
5050
BlocProvider<FurnitureCubit>(create: (context) => FurnitureCubit()),
5151
BlocProvider<UnsetslotCubit>(create: (context) => UnsetslotCubit()),
5252
BlocProvider<Start2GetDataCubit>(create: (context) => Start2GetDataCubit()),
53+
BlocProvider<QuestlistCubit>(create: (context) => QuestlistCubit()),
5354
],
5455
child: BlocConsumer<GlobalBloc, GlobalState>(
5556
listener: (context, state) {},

lib/screens/fleet_formation.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import 'package:flutter/widgets.dart';
2+
3+
class FleetFormation extends StatefulWidget {
4+
const FleetFormation({super.key, required int id});
5+
6+
@override
7+
State<StatefulWidget> createState() => FleetFormationState();
8+
}
9+
10+
class FleetFormationState extends State<FleetFormation> {
11+
@override
12+
Widget build(BuildContext context) {
13+
return Container();
14+
}
15+
}

lib/screens/home.dart

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,25 +84,32 @@ class _HomeViewState extends State<HomeView>
8484
label: 'dry dock',
8585
onSelected: () {
8686
print('Send');
87-
_layout.addItemOnRoot(newItem: DockingView.createDryDock(), dropPosition: DropPosition.top);
87+
_layout.addItemOnRoot(
88+
newItem: DockingView.createDryDock(),
89+
dropPosition: DropPosition.top);
8890
},
8991
),
9092
PlatformMenuItem(
9193
label: 'FleetForcesCommand',
9294
onSelected: () {},
9395
),
9496
PlatformMenuItem(
95-
label: 'task',
97+
label: 'quest',
9698
onSelected: () {
97-
print('Receive');
99+
print('Send');
100+
_layout.addItemOnRoot(
101+
newItem: DockingView.createQuestlist(),
102+
dropPosition: DropPosition.top);
98103
},
99104
),
100105
]),
101106
]),
102107
PlatformMenuItem(
103-
label: 'task',
108+
label: 'quest',
104109
onSelected: () {
105-
print('Receive');
110+
_layout.addItemOnRoot(
111+
newItem: DockingView.createQuestlist(),
112+
dropPosition: DropPosition.top);
106113
},
107114
),
108115
]),

lib/screens/mod.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export 'home.dart';
22
export 'ffc.dart';
33
export 'drydock.dart';
4+
export 'fleet_formation.dart';
5+
export 'questlist.dart';
46
export 'settings/setting.dart';

lib/screens/questlist.dart

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import 'package:fluent_ui/fluent_ui.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:squadron_en_route/components/kancolle_model/kancolle_model.dart';
4+
import 'package:squadron_en_route/helper/mod.dart';
5+
6+
class QuestlistView extends StatefulWidget {
7+
const QuestlistView({super.key});
8+
9+
@override
10+
State<StatefulWidget> createState() => QuestlistViewState();
11+
}
12+
13+
class QuestlistViewState extends State<QuestlistView> {
14+
late int apiCount;
15+
late int apiCompletedKind;
16+
late List<Quest> apiList = [];
17+
late int apiExecCount;
18+
late List<ApiClist> apiCList;
19+
late int apiExecType;
20+
21+
@override
22+
void initState() {
23+
super.initState();
24+
apiList = [];
25+
}
26+
27+
@override
28+
Widget build(BuildContext context) {
29+
return BlocListener<QuestlistCubit, QuestlistState>(
30+
listener: (context, state) {
31+
state.when(
32+
initial: () {},
33+
loaded: (apiCount, apiCompletedKind, apiList, apiExecCount,
34+
apiCList, apiExecType) {
35+
this.apiCount = apiCount;
36+
this.apiCompletedKind = apiCompletedKind;
37+
this.apiList = List.from(apiList);
38+
this.apiExecCount = apiExecCount;
39+
this.apiCList = apiCList;
40+
this.apiExecType = apiExecType;
41+
setState(() {});
42+
},
43+
);
44+
},
45+
child: Column(children: [
46+
CommandBar(primaryItems: [
47+
CommandBarBuilderItem(
48+
builder: (context, mode, w) => Tooltip(
49+
message: context.L.webviewCameraTakePic,
50+
child: w,
51+
),
52+
wrappedItem: CommandBarButton(
53+
icon: const Icon(FluentIcons.increase_indent),
54+
onPressed: () {
55+
setState(() {
56+
apiList.sort(
57+
(a, b) => b.apiState.index.compareTo(a.apiState.index));
58+
});
59+
},
60+
),
61+
),
62+
]),
63+
Expanded(
64+
child: ListView.builder(
65+
itemBuilder: (context, index) {
66+
return Tooltip(
67+
message: apiList[index].apiDetail,
68+
child: ListTile.selectable(
69+
leading: Text('月'),
70+
title: Text(apiList[index].apiTitle),
71+
trailing: Text(apiList[index].apiState.toString()),
72+
selected:
73+
apiList[index].apiState != QuestState.unaccepted,
74+
));
75+
},
76+
itemCount: apiList.length)),
77+
]));
78+
}
79+
}

0 commit comments

Comments
 (0)