Skip to content

Commit 59987a1

Browse files
authored
Merge pull request #348 from DevKor-github/feat/investigate-schedule-data-flow
Ensure calendar updates after schedule saves without reload
2 parents b3eec18 + 0c1962f commit 59987a1

9 files changed

Lines changed: 1173 additions & 155 deletions

File tree

lib/data/repositories/schedule_repository_impl.dart

Lines changed: 38 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
1414
final ScheduleRemoteDataSource scheduleRemoteDataSource;
1515

1616
late final _scheduleStreamController =
17-
BehaviorSubject<Set<ScheduleEntity>>.seeded(
18-
const <ScheduleEntity>{},
19-
);
17+
BehaviorSubject<Set<ScheduleEntity>>.seeded(const <ScheduleEntity>{});
2018

2119
ScheduleRepositoryImpl({
2220
required this.scheduleLocalDataSource,
@@ -32,8 +30,9 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
3230
try {
3331
await scheduleRemoteDataSource.createSchedule(schedule);
3432
//await scheduleLocalDataSource.createSchedule(schedule);
35-
_scheduleStreamController
36-
.add(Set.from(_scheduleStreamController.value)..add(schedule));
33+
_scheduleStreamController.add(
34+
Set.from(_scheduleStreamController.value)..add(schedule),
35+
);
3736
} catch (e) {
3837
rethrow;
3938
}
@@ -44,8 +43,9 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
4443
try {
4544
await scheduleRemoteDataSource.deleteSchedule(schedule);
4645
//await scheduleLocalDataSource.deleteSchedule(schedule);
47-
_scheduleStreamController
48-
.add(Set.from(_scheduleStreamController.value)..remove(schedule));
46+
_scheduleStreamController.add(
47+
Set.from(_scheduleStreamController.value)..remove(schedule),
48+
);
4949
} catch (e) {
5050
rethrow;
5151
}
@@ -55,8 +55,9 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
5555
Future<ScheduleEntity> getScheduleById(String id) async {
5656
try {
5757
final schedule = await scheduleRemoteDataSource.getScheduleById(id);
58-
_scheduleStreamController
59-
.add(Set.from(_scheduleStreamController.value)..add(schedule));
58+
_scheduleStreamController.add(
59+
Set.from(_scheduleStreamController.value)..add(schedule),
60+
);
6061
return schedule;
6162
} catch (e) {
6263
rethrow;
@@ -65,12 +66,22 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
6566

6667
@override
6768
Future<List<ScheduleEntity>> getSchedulesByDate(
68-
DateTime startDate, DateTime? endDate) async {
69+
DateTime startDate,
70+
DateTime? endDate,
71+
) async {
6972
try {
70-
final schedules =
71-
await scheduleRemoteDataSource.getSchedulesByDate(startDate, endDate);
72-
_scheduleStreamController
73-
.add(Set.from(_scheduleStreamController.value)..addAll(schedules));
73+
final schedules = await scheduleRemoteDataSource.getSchedulesByDate(
74+
startDate,
75+
endDate,
76+
);
77+
final mergedSchedules = Set<ScheduleEntity>.from(
78+
_scheduleStreamController.value,
79+
);
80+
for (final schedule in schedules) {
81+
mergedSchedules.removeWhere((existing) => existing.id == schedule.id);
82+
mergedSchedules.add(schedule);
83+
}
84+
_scheduleStreamController.add(mergedSchedules);
7485
return schedules;
7586
} catch (e) {
7687
rethrow;
@@ -81,9 +92,11 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
8192
Future<void> updateSchedule(ScheduleEntity schedule) async {
8293
try {
8394
await scheduleRemoteDataSource.updateSchedule(schedule);
84-
_scheduleStreamController.add(Set.from(_scheduleStreamController.value)
85-
..remove(schedule)
86-
..add(schedule));
95+
_scheduleStreamController.add(
96+
Set.from(_scheduleStreamController.value)
97+
..remove(schedule)
98+
..add(schedule),
99+
);
87100
//await scheduleLocalDataSource.updateSchedule(schedule);
88101
} catch (e) {
89102
rethrow;
@@ -97,11 +110,14 @@ class ScheduleRepositoryImpl implements ScheduleRepository {
97110
final lateStatus = latenessTime > 0
98111
? ScheduleDoneStatus.lateEnd
99112
: ScheduleDoneStatus.normalEnd;
100-
final schedule = _scheduleStreamController.value
101-
.firstWhere((schedule) => schedule.id == scheduleId);
102-
_scheduleStreamController.add(Set.from(_scheduleStreamController.value)
103-
..remove(schedule)
104-
..add(schedule.copyWith(doneStatus: lateStatus)));
113+
final schedule = _scheduleStreamController.value.firstWhere(
114+
(schedule) => schedule.id == scheduleId,
115+
);
116+
_scheduleStreamController.add(
117+
Set.from(_scheduleStreamController.value)
118+
..remove(schedule)
119+
..add(schedule.copyWith(doneStatus: lateStatus)),
120+
);
105121
} catch (e) {
106122
rethrow;
107123
}

lib/presentation/calendar/component/schedule_detail.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,10 @@ class _ScheduleDetailState extends State<ScheduleDetail> {
7979
!widget.schedule.scheduleTime.isBefore(DateTime.now());
8080
return [
8181
SwipeAction(
82-
onTap: (controller) => widget.onDeleted?.call(),
82+
onTap: (handler) async {
83+
await handler(false);
84+
widget.onDeleted?.call();
85+
},
8386
color: Colors.transparent,
8487
content: _SwipeActionContent(
8588
icon: const _TrashCanSvg(),
@@ -89,7 +92,10 @@ class _ScheduleDetailState extends State<ScheduleDetail> {
8992
if (canEdit)
9093
SwipeAction(
9194
widthSpace: 96,
92-
onTap: (controller) => widget.onEdit?.call(),
95+
onTap: (handler) async {
96+
await handler(false);
97+
widget.onEdit?.call();
98+
},
9399
color: Colors.transparent,
94100
content: _SwipeActionContent(
95101
icon: const _EditPencilSvg(),

lib/presentation/schedule_create/bloc/schedule_form_bloc.dart

Lines changed: 136 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -59,40 +59,54 @@ class ScheduleFormBloc extends Bloc<ScheduleFormEvent, ScheduleFormState> {
5959
ScheduleFormEditRequested event,
6060
Emitter<ScheduleFormState> emit,
6161
) async {
62-
emit(state.copyWith(
63-
status: ScheduleFormStatus.loading,
64-
));
62+
emit(
63+
state.copyWith(
64+
status: ScheduleFormStatus.loading,
65+
submissionStatus: ScheduleFormSubmissionStatus.idle,
66+
submissionError: null,
67+
),
68+
);
6569

6670
await _loadPreparationByScheduleIdUseCase(event.scheduleId);
6771
final PreparationEntity preparationEntity =
6872
await _getPreparationByScheduleIdUseCase(event.scheduleId);
6973

70-
final ScheduleEntity scheduleEntity =
71-
await _getScheduleByIdUseCase(event.scheduleId);
72-
73-
emit(state.copyWith(
74-
status: ScheduleFormStatus.success,
75-
id: scheduleEntity.id,
76-
placeName: scheduleEntity.place.placeName,
77-
scheduleName: scheduleEntity.scheduleName,
78-
scheduleTime: scheduleEntity.scheduleTime,
79-
moveTime: scheduleEntity.moveTime,
80-
isChanged: scheduleEntity.isChanged
81-
? IsPreparationChanged.changed
82-
: IsPreparationChanged.unchanged,
83-
scheduleSpareTime: scheduleEntity.scheduleSpareTime,
84-
scheduleNote: scheduleEntity.scheduleNote,
85-
preparation: preparationEntity,
86-
));
74+
final ScheduleEntity scheduleEntity = await _getScheduleByIdUseCase(
75+
event.scheduleId,
76+
);
77+
78+
emit(
79+
state.copyWith(
80+
status: ScheduleFormStatus.success,
81+
submissionStatus: ScheduleFormSubmissionStatus.idle,
82+
submissionError: null,
83+
id: scheduleEntity.id,
84+
placeId: scheduleEntity.place.id,
85+
placeName: scheduleEntity.place.placeName,
86+
scheduleName: scheduleEntity.scheduleName,
87+
scheduleTime: scheduleEntity.scheduleTime,
88+
moveTime: scheduleEntity.moveTime,
89+
isChanged: scheduleEntity.isChanged
90+
? IsPreparationChanged.changed
91+
: IsPreparationChanged.unchanged,
92+
scheduleSpareTime: scheduleEntity.scheduleSpareTime,
93+
scheduleNote: scheduleEntity.scheduleNote,
94+
preparation: preparationEntity,
95+
),
96+
);
8797
}
8898

8999
void _onCreateRequested(
90100
ScheduleFormCreateRequested event,
91101
Emitter<ScheduleFormState> emit,
92102
) async {
93-
emit(state.copyWith(
94-
status: ScheduleFormStatus.loading,
95-
));
103+
emit(
104+
state.copyWith(
105+
status: ScheduleFormStatus.loading,
106+
submissionStatus: ScheduleFormSubmissionStatus.idle,
107+
submissionError: null,
108+
),
109+
);
96110

97111
final PreparationEntity defaultPreparationStepList =
98112
await _getDefaultPreparationUseCase();
@@ -112,18 +126,23 @@ class ScheduleFormBloc extends Bloc<ScheduleFormEvent, ScheduleFormState> {
112126
now.minute,
113127
);
114128

115-
emit(state.copyWith(
116-
status: ScheduleFormStatus.success,
117-
id: Uuid().v7(),
118-
placeName: null,
119-
scheduleName: null,
120-
scheduleTime: initialScheduleTime,
121-
moveTime: null,
122-
isChanged: null,
123-
scheduleSpareTime: userSpareTime,
124-
scheduleNote: null,
125-
preparation: defaultPreparationStepList,
126-
));
129+
emit(
130+
state.copyWith(
131+
status: ScheduleFormStatus.success,
132+
submissionStatus: ScheduleFormSubmissionStatus.idle,
133+
submissionError: null,
134+
id: Uuid().v7(),
135+
placeId: Uuid().v7(),
136+
placeName: null,
137+
scheduleName: null,
138+
scheduleTime: null,
139+
moveTime: null,
140+
isChanged: null,
141+
scheduleSpareTime: userSpareTime,
142+
scheduleNote: null,
143+
preparation: defaultPreparationStepList,
144+
),
145+
);
127146
}
128147

129148
void _onScheduleNameChanged(
@@ -137,17 +156,19 @@ class ScheduleFormBloc extends Bloc<ScheduleFormEvent, ScheduleFormState> {
137156
ScheduleFormScheduleDateTimeChanged event,
138157
Emitter<ScheduleFormState> emit,
139158
) {
140-
emit(state.copyWith(
141-
scheduleTime: DateTime(
142-
event.scheduleDate.year,
143-
event.scheduleDate.month,
144-
event.scheduleDate.day,
145-
event.scheduleTime.hour,
146-
event.scheduleTime.minute,
159+
emit(
160+
state.copyWith(
161+
scheduleTime: DateTime(
162+
event.scheduleDate.year,
163+
event.scheduleDate.month,
164+
event.scheduleDate.day,
165+
event.scheduleTime.hour,
166+
event.scheduleTime.minute,
167+
),
168+
maxAvailableTime: event.maxAvailableTime,
169+
previousScheduleName: event.previousScheduleName,
147170
),
148-
maxAvailableTime: event.maxAvailableTime,
149-
previousScheduleName: event.previousScheduleName,
150-
));
171+
);
151172
}
152173

153174
void _onPlaceNameChanged(
@@ -183,38 +204,93 @@ class ScheduleFormBloc extends Bloc<ScheduleFormEvent, ScheduleFormState> {
183204
isChagned = IsPreparationChanged.changed;
184205
}
185206

186-
emit(state.copyWith(
187-
preparation: event.preparation,
188-
isChanged: isChagned,
189-
));
207+
emit(state.copyWith(preparation: event.preparation, isChanged: isChagned));
190208
}
191209

192210
Future<void> _onUpdated(
193211
ScheduleFormUpdated event,
194212
Emitter<ScheduleFormState> emit,
195213
) async {
196-
final ScheduleEntity scheduleEntity = state.createEntity(state);
197-
await _updateScheduleUseCase(scheduleEntity);
198-
if (state.isChanged != IsPreparationChanged.unchanged) {
199-
_updatePreparationByScheduleIdUseCase(
200-
state.preparation!, scheduleEntity.id);
214+
if (state.submissionStatus == ScheduleFormSubmissionStatus.submitting) {
215+
return;
216+
}
217+
218+
emit(
219+
state.copyWith(
220+
submissionStatus: ScheduleFormSubmissionStatus.submitting,
221+
submissionError: null,
222+
),
223+
);
224+
225+
try {
226+
final ScheduleEntity scheduleEntity = state.createEntity(state);
227+
await _updateScheduleUseCase(scheduleEntity);
228+
if (state.isChanged != IsPreparationChanged.unchanged) {
229+
await _updatePreparationByScheduleIdUseCase(
230+
state.preparation!,
231+
scheduleEntity.id,
232+
);
233+
}
234+
emit(
235+
state.copyWith(
236+
submissionStatus: ScheduleFormSubmissionStatus.success,
237+
submissionError: null,
238+
),
239+
);
240+
} catch (e) {
241+
emit(
242+
state.copyWith(
243+
submissionStatus: ScheduleFormSubmissionStatus.failure,
244+
submissionError: e.toString(),
245+
),
246+
);
201247
}
202248
}
203249

204250
Future<void> _onCreated(
205251
ScheduleFormCreated event,
206252
Emitter<ScheduleFormState> emit,
207253
) async {
208-
final ScheduleEntity scheduleEntity = state.createEntity(state);
209-
await _createScheduleWithPlaceUseCase(scheduleEntity);
210-
if (state.isChanged != IsPreparationChanged.unchanged) {
211-
await _createCustomPreparationUseCase(
212-
state.preparation!, scheduleEntity.id);
254+
if (state.submissionStatus == ScheduleFormSubmissionStatus.submitting) {
255+
return;
256+
}
257+
258+
emit(
259+
state.copyWith(
260+
submissionStatus: ScheduleFormSubmissionStatus.submitting,
261+
submissionError: null,
262+
),
263+
);
264+
265+
try {
266+
final ScheduleEntity scheduleEntity = state.createEntity(state);
267+
await _createScheduleWithPlaceUseCase(scheduleEntity);
268+
if (state.isChanged != IsPreparationChanged.unchanged) {
269+
await _createCustomPreparationUseCase(
270+
state.preparation!,
271+
scheduleEntity.id,
272+
);
273+
}
274+
emit(
275+
state.copyWith(
276+
submissionStatus: ScheduleFormSubmissionStatus.success,
277+
submissionError: null,
278+
),
279+
);
280+
} catch (e) {
281+
emit(
282+
state.copyWith(
283+
submissionStatus: ScheduleFormSubmissionStatus.failure,
284+
submissionError: e.toString(),
285+
),
286+
);
213287
}
214288
}
215289

216290
void _onValidated(
217-
ScheduleFormValidated event, Emitter<ScheduleFormState> emit) {
291+
ScheduleFormValidated event,
292+
Emitter<ScheduleFormState> emit,
293+
) {
218294
emit(state.copyWith(isValid: event.isValid));
219295
}
220296
}

0 commit comments

Comments
 (0)