Skip to content

Commit 1ec95bb

Browse files
committed
Allow specifing sources in bloc
1 parent 6a68772 commit 1ec95bb

File tree

7 files changed

+151
-208
lines changed

7 files changed

+151
-208
lines changed

app/lib/blocs/sourced_paging.dart

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class SourcedPagingBloc<T>
1818
final FlowCubit cubit;
1919
final int pageSize;
2020
final bool useDates;
21+
final List<String>? sources;
2122
final Future<List<T>?> Function(
2223
String source,
2324
SourceService service,
@@ -28,6 +29,7 @@ class SourcedPagingBloc<T>
2829

2930
SourcedPagingBloc.dated(
3031
{required this.cubit,
32+
this.sources,
3133
required Future<List<T>?> Function(String source, SourceService service,
3234
int offset, int limit, int date)
3335
fetch,
@@ -40,6 +42,7 @@ class SourcedPagingBloc<T>
4042

4143
SourcedPagingBloc.simple(
4244
{required this.cubit,
45+
this.sources,
4346
required Future<List<T>?> Function(
4447
String source, SourceService service, int offset, int limit)
4548
fetch,
@@ -56,6 +59,19 @@ class SourcedPagingBloc<T>
5659
emit(const SourcedPagingInitial());
5760
fetch();
5861
});
62+
on<SourcedPagingRemoved>((event, emit) {
63+
final state = this.state;
64+
if (state is SourcedPagingSuccess<T>) {
65+
final items =
66+
state.dates.map((e) => e.where((i) => i != event.item).toList());
67+
emit(SourcedPagingSuccess(
68+
currentPageKey: state.currentPageKey,
69+
dates: items.toList(),
70+
hasReachedMax: state.hasReachedMax,
71+
currentDate: state.currentDate,
72+
));
73+
}
74+
});
5975
fetch();
6076
}
6177

@@ -84,7 +100,7 @@ class SourcedPagingBloc<T>
84100
.map((e) => SourcedModel(currentPageKey.source, e))
85101
.toList();
86102

87-
final sources = cubit.getCurrentSources();
103+
final sources = this.sources ?? cubit.getCurrentSources();
88104
final currentSourceIndex = sources.indexOf(currentPageKey.source);
89105
final keepSource = fetchedItems.length >= pageSize;
90106
final isLastSource = currentSourceIndex >= sources.length - 1;
@@ -133,6 +149,8 @@ class SourcedPagingBloc<T>
133149
void fetch() {
134150
add(SourcedPagingFetched());
135151
}
152+
153+
void remove(SourcedModel<T> item) => add(SourcedPagingRemoved(item));
136154
}
137155

138156
_buildDatedFetch<T>(

app/lib/blocs/sourced_paging_event.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ class SourcedPagingRefresh extends SourcedPagingEvent {
1818
@override
1919
List<Object> get props => [];
2020
}
21+
22+
class SourcedPagingRemoved extends SourcedPagingEvent {
23+
final Object item;
24+
25+
SourcedPagingRemoved(this.item);
26+
27+
@override
28+
List<Object> get props => [item];
29+
}

app/lib/pages/events/page.dart

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
1+
import 'package:flow/blocs/sourced_paging.dart';
12
import 'package:flow/pages/events/event.dart';
2-
import 'package:flow/widgets/builder_delegate.dart';
33
import 'package:flow/widgets/navigation.dart';
4+
import 'package:flow/widgets/paging/list.dart';
45
import 'package:flutter/material.dart';
56
import 'package:flutter_bloc/flutter_bloc.dart';
67
import 'package:flow/src/generated/i18n/app_localizations.dart';
7-
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
88
import 'package:phosphor_flutter/phosphor_flutter.dart';
99
import 'package:flow_api/models/event/model.dart';
10-
import 'package:flow_api/models/model.dart';
1110

1211
import '../../cubits/flow.dart';
13-
import '../../helpers/sourced_paging_controller.dart';
1412
import 'filter.dart';
1513
import 'tile.dart';
1614

@@ -105,28 +103,29 @@ class EventsBodyView extends StatefulWidget {
105103

106104
class _EventsBodyViewState extends State<EventsBodyView> {
107105
late final FlowCubit _flowCubit;
108-
late final SourcedPagingController<Event> _controller;
106+
late final SourcedPagingBloc<Event> _bloc;
109107
late EventFilter _filter;
110108

111109
@override
112110
void initState() {
113111
_flowCubit = context.read<FlowCubit>();
114-
_controller = SourcedPagingController(_flowCubit);
115-
_controller.addFetchListener((source, service, offset, limit) async =>
116-
_filter.source != null && _filter.source != source
117-
? null
118-
: service.event?.getEvents(
119-
offset: offset,
120-
limit: limit,
121-
groupId: _filter.source == source ? _filter.group : null,
122-
search: widget.search));
112+
_bloc = SourcedPagingBloc.simple(
113+
cubit: _flowCubit,
114+
fetch: (source, service, offset, limit) async =>
115+
_filter.source != null && _filter.source != source
116+
? null
117+
: service.event?.getEvents(
118+
offset: offset,
119+
limit: limit,
120+
groupId: _filter.source == source ? _filter.group : null,
121+
search: widget.search));
123122
_filter = widget.filter;
124123
super.initState();
125124
}
126125

127126
@override
128127
void dispose() {
129-
_controller.dispose();
128+
_bloc.close();
130129
super.dispose();
131130
}
132131

@@ -135,7 +134,7 @@ class _EventsBodyViewState extends State<EventsBodyView> {
135134
super.didUpdateWidget(oldWidget);
136135

137136
if (oldWidget.search != widget.search) {
138-
_controller.refresh();
137+
_bloc.refresh();
139138
}
140139
}
141140

@@ -150,37 +149,34 @@ class _EventsBodyViewState extends State<EventsBodyView> {
150149
setState(() {
151150
_filter = filter;
152151
});
153-
_controller.refresh();
152+
_bloc.refresh();
154153
},
155154
),
156155
const SizedBox(height: 8),
157156
Expanded(
158-
child: PagedListView(
159-
pagingController: _controller,
160-
builderDelegate: buildMaterialPagedDelegate<SourcedModel<Event>>(
161-
_controller,
162-
(ctx, item, index) => Align(
163-
alignment: Alignment.topCenter,
164-
child: Container(
165-
constraints: const BoxConstraints(maxWidth: 800),
166-
child: Dismissible(
167-
key: ValueKey('${item.model.id}@${item.source}'),
168-
onDismissed: (direction) async {
169-
await _flowCubit
170-
.getService(item.source)
171-
.event
172-
?.deleteEvent(item.model.id!);
173-
_controller.itemList!.remove(item);
174-
},
175-
background: Container(
176-
color: Colors.red,
177-
),
178-
child: EventTile(
179-
flowCubit: _flowCubit,
180-
pagingController: _controller,
181-
source: item.source,
182-
event: item.model,
183-
),
157+
child: PagedListView.simple(
158+
bloc: _bloc,
159+
itemBuilder: (ctx, item, index) => Align(
160+
alignment: Alignment.topCenter,
161+
child: Container(
162+
constraints: const BoxConstraints(maxWidth: 800),
163+
child: Dismissible(
164+
key: ValueKey('${item.model.id}@${item.source}'),
165+
onDismissed: (direction) async {
166+
await _flowCubit
167+
.getService(item.source)
168+
.event
169+
?.deleteEvent(item.model.id!);
170+
_bloc.remove(item);
171+
},
172+
background: Container(
173+
color: Colors.red,
174+
),
175+
child: EventTile(
176+
flowCubit: _flowCubit,
177+
bloc: _bloc,
178+
source: item.source,
179+
event: item.model,
184180
),
185181
),
186182
),
@@ -192,7 +188,7 @@ class _EventsBodyViewState extends State<EventsBodyView> {
192188
floatingActionButton: FloatingActionButton.extended(
193189
onPressed: () => showDialog(
194190
context: context, builder: (context) => const EventDialog())
195-
.then((_) => _controller.refresh()),
191+
.then((_) => _bloc.refresh()),
196192
label: Text(AppLocalizations.of(context).create),
197193
icon: const PhosphorIcon(PhosphorIconsLight.plus),
198194
),

app/lib/pages/events/tile.dart

Lines changed: 6 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
1+
import 'package:flow/blocs/sourced_paging.dart';
12
import 'package:flutter/material.dart';
2-
import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:flow/src/generated/i18n/app_localizations.dart';
44
import 'package:go_router/go_router.dart';
5-
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
65
import 'package:material_leap/material_leap.dart';
76
import 'package:phosphor_flutter/phosphor_flutter.dart';
87
import 'package:flow_api/models/event/model.dart';
98
import 'package:flow_api/models/model.dart';
109

1110
import '../../cubits/flow.dart';
12-
import '../../helpers/sourced_paging_controller.dart';
13-
import '../../widgets/builder_delegate.dart';
1411
import '../../widgets/markdown_field.dart';
1512
import '../calendar/filter.dart';
1613
import 'event.dart';
@@ -21,13 +18,13 @@ class EventTile extends StatelessWidget {
2118
required this.source,
2219
required this.event,
2320
required this.flowCubit,
24-
required this.pagingController,
21+
required this.bloc,
2522
});
2623

2724
final FlowCubit flowCubit;
2825
final Event event;
2926
final String source;
30-
final SourcedPagingController<Event> pagingController;
27+
final SourcedPagingBloc<Event> bloc;
3128

3229
@override
3330
Widget build(BuildContext context) {
@@ -87,11 +84,11 @@ class EventTile extends StatelessWidget {
8784
onPressed: () async {
8885
Navigator.of(context).pop();
8986
await flowCubit.getService(source).event?.deleteEvent(event.id!);
90-
pagingController.itemList!.remove(SourcedModel(
87+
bloc.remove(SourcedModel(
9188
source,
9289
event,
9390
));
94-
pagingController.refresh();
91+
bloc.refresh();
9592
},
9693
child: Text(
9794
AppLocalizations.of(context).delete,
@@ -109,57 +106,6 @@ class EventTile extends StatelessWidget {
109106
event: event,
110107
source: source,
111108
),
112-
).then((value) => pagingController.refresh());
109+
).then((value) => bloc.refresh());
113110
}
114111
}
115-
116-
Future<SourcedModel<Event>?> showEventModalBottomSheet(
117-
{required BuildContext context, Event? event, DateTime? time}) async {
118-
SourcedModel<Event>? event;
119-
final cubit = context.read<FlowCubit>();
120-
final pagingController = SourcedPagingController<Event>(cubit);
121-
pagingController.addFetchListener((source, service, offset, limit) async =>
122-
service.event?.getEvents(offset: offset, limit: limit));
123-
final shouldCreate = await showLeapBottomSheet<bool>(
124-
context: context,
125-
titleBuilder: (ctx) => Text(AppLocalizations.of(context).events),
126-
actionsBuilder: (ctx) => [
127-
TextButton.icon(
128-
icon: const PhosphorIcon(PhosphorIconsLight.plusCircle),
129-
label: Text(AppLocalizations.of(context).create),
130-
onPressed: () {
131-
Navigator.of(ctx).pop(true);
132-
},
133-
),
134-
],
135-
childrenBuilder: (ctx) => [
136-
PagedListView(
137-
shrinkWrap: true,
138-
pagingController: pagingController,
139-
builderDelegate:
140-
buildMaterialPagedDelegate<SourcedModel<Event>>(
141-
pagingController,
142-
(ctx, item, index) {
143-
return ListTile(
144-
title: Text(item.model.name),
145-
leading: const PhosphorIcon(PhosphorIconsLight.calendar),
146-
onTap: () {
147-
event = item;
148-
Navigator.of(ctx).pop();
149-
},
150-
);
151-
},
152-
)),
153-
]);
154-
pagingController.dispose();
155-
if (shouldCreate == true && context.mounted) {
156-
event = await showDialog(
157-
context: context,
158-
builder: (ctx) => EventDialog(
159-
event: event?.model,
160-
source: event?.source,
161-
),
162-
);
163-
}
164-
return event;
165-
}

0 commit comments

Comments
 (0)