Skip to content

Commit

Permalink
refactor(notification): separate notification types
Browse files Browse the repository at this point in the history
  • Loading branch information
realth000 committed Oct 9, 2024
1 parent a93d27a commit 1d06eda
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 169 deletions.
157 changes: 90 additions & 67 deletions lib/features/notification/bloc/notification_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,84 +9,107 @@ part 'notification_event.dart';
part 'notification_state.dart';

/// Emitter
typedef _Emit = Emitter<NotificationState>;
typedef _Emit<M, T extends NotificationBaseState<M>> = Emitter<T>;

/// Bloc of notification.
class NotificationBloc extends Bloc<NotificationEvent, NotificationState>
with LoggerMixin {
class NotificationBaseBloc<M, T extends NotificationBaseState<M>>
extends Bloc<NotificationEvent, T> with LoggerMixin {
/// Constructor.
NotificationBloc({required NotificationRepository notificationRepository})
: _notificationRepository = notificationRepository,
super(const NotificationState()) {
on<NotificationRefreshNoticeRequired>(_onNotificationRefreshNoticeRequired);
on<NotificationRefreshPersonalMessageRequired>(
_onNotificationRefreshPersonalMessageRequired,
);
on<NotificationRefreshBroadcastMessageRequired>(
_onNotificationRefreshBroadcastMessageRequired,
NotificationBaseBloc({
required NotificationRepository notificationRepository,
required T initialState,
}) : _notificationRepository = notificationRepository,
super(initialState) {
on<NotificationEvent>(
(event, emit) => switch (event) {
NotificationRefreshRequested() => _onRefreshRequested(emit),
NotificationLoadMoreRequested() => _onLoadRequested(emit),
},
);
}

final NotificationRepository _notificationRepository;

Future<void> _onNotificationRefreshNoticeRequired(
NotificationRefreshNoticeRequired event,
_Emit emit,
) async {
emit(state.copyWith(noticeStatus: NotificationStatus.loading));
await _notificationRepository.fetchNotice().match((e) {
handle(e);
error('failed to fetch notice: $e');
emit(state.copyWith(noticeStatus: NotificationStatus.failed));
}, (v) {
final noticeList = v;
emit(
state.copyWith(
noticeStatus: NotificationStatus.success,
noticeList: noticeList,
),
);
}).run();
Future<void> _onRefreshRequested(_Emit<M, T> emit) async {
emit(state.copyWith(status: NotificationStatus.loading) as T);
switch (T) {
case NoticeState:
await _notificationRepository.fetchNotice().match((e) {
handle(e);
error('failed to fetch notice: $e');
emit(state.copyWith(status: NotificationStatus.failure) as T);
}, (v) {
final noticeList = v.notificationList;
emit(
state.copyWith(
status: NotificationStatus.success,
noticeList: noticeList as List<M>,
) as T,
);
}).run();
case PersonalMessageState:
await _notificationRepository.fetchPersonalMessage().match((e) {
handle(e);
error('failed to fetch notice: $e');
emit(state.copyWith(status: NotificationStatus.failure) as T);
}, (v) {
final noticeList = v;
emit(
state.copyWith(
status: NotificationStatus.success,
noticeList: noticeList as List<M>,
) as T,
);
}).run();
case BroadcastMessageState:
await _notificationRepository.fetchBroadMessage().match((e) {
handle(e);
error('failed to fetch notice: $e');
emit(state.copyWith(status: NotificationStatus.failure) as T);
}, (v) {
final noticeList = v;
emit(
state.copyWith(
status: NotificationStatus.success,
noticeList: noticeList as List<M>,
) as T,
);
}).run();
case Type():
throw UnimplementedError('notification type not implemented: $T');
}
}

Future<void> _onNotificationRefreshPersonalMessageRequired(
NotificationRefreshPersonalMessageRequired event,
_Emit emit,
) async {
emit(state.copyWith(personalMessageStatus: NotificationStatus.loading));
await _notificationRepository.fetchPersonalMessage().match((e) {
handle(e);
error('failed to fetch private messages: $e');
emit(state.copyWith(personalMessageStatus: NotificationStatus.failed));
}, (v) {
final privateMessageList = v;
emit(
state.copyWith(
personalMessageStatus: NotificationStatus.success,
personalMessageList: privateMessageList,
),
);
}).run();
Future<void> _onLoadRequested(_Emit<M, T> emit) async {
throw UnimplementedError('implement load pages');
}
}

Future<void> _onNotificationRefreshBroadcastMessageRequired(
NotificationRefreshBroadcastMessageRequired event,
_Emit emit,
) async {
emit(state.copyWith(broadcastMessageStatus: NotificationStatus.loading));
await _notificationRepository.fetchBroadMessage().match((e) {
handle(e);
error('failed to fetch broad messages: $e');
emit(state.copyWith(broadcastMessageStatus: NotificationStatus.failed));
}, (v) {
final broadcastMessageList = v;
/// Bloc of notice type notification.
final class NoticeBloc extends NotificationBaseBloc<Notice, NoticeState> {
/// Constructor.
NoticeBloc({required super.notificationRepository})
: super(
initialState: const NoticeState(),
);
}

emit(
state.copyWith(
broadcastMessageStatus: NotificationStatus.success,
broadcastMessageList: broadcastMessageList,
),
);
}).run();
}
/// Bloc of personal message type notification.
final class PersonalMessageBloc
extends NotificationBaseBloc<PersonalMessage, PersonalMessageState> {
/// Constructor.
PersonalMessageBloc({required super.notificationRepository})
: super(
initialState: const PersonalMessageState(),
);
}

/// Bloc of broadcast message type notification.
final class BroadcastMessageBloc
extends NotificationBaseBloc<BroadcastMessage, BroadcastMessageState> {
/// Constructor.
BroadcastMessageBloc({required super.notificationRepository})
: super(
initialState: const BroadcastMessageState(),
);
}
18 changes: 6 additions & 12 deletions lib/features/notification/bloc/notification_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,12 @@ sealed class NotificationEvent with NotificationEventMappable {
const NotificationEvent();
}

/// User required to refresh the notification page.
/// Requested to refresh notification.
@MappableClass()
final class NotificationRefreshNoticeRequired extends NotificationEvent
with NotificationRefreshNoticeRequiredMappable {}
final class NotificationRefreshRequested extends NotificationEvent
with NotificationRefreshRequestedMappable {}

/// User required to refresh the private personal message tab.
/// Requested to load more notification from the next page.
@MappableClass()
final class NotificationRefreshPersonalMessageRequired extends NotificationEvent
with NotificationRefreshPersonalMessageRequiredMappable {}

/// User required to refresh the broadcast message tab.
@MappableClass()
final class NotificationRefreshBroadcastMessageRequired
extends NotificationEvent
with NotificationRefreshBroadcastMessageRequiredMappable {}
final class NotificationLoadMoreRequested extends NotificationEvent
with NotificationLoadMoreRequestedMappable {}
80 changes: 59 additions & 21 deletions lib/features/notification/bloc/notification_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,37 +12,75 @@ enum NotificationStatus {
success,

/// Failed.
failed,
failure,
}

/// State of notification.
/// Basic notification.
///
/// Common members of notification where T can be:
///
/// * [Notice]
/// * [PersonalMessage].
/// * [BroadcastMessage].
@MappableClass()
class NotificationState with NotificationStateMappable {
sealed class NotificationBaseState<T> with NotificationBaseStateMappable<T> {
/// Constructor.
const NotificationState({
this.noticeStatus = NotificationStatus.initial,
this.personalMessageStatus = NotificationStatus.initial,
this.broadcastMessageStatus = NotificationStatus.initial,
const NotificationBaseState({
this.status = NotificationStatus.initial,
this.pageNumber = 1,
this.hasNextPage = false,
this.noticeList = const [],
this.personalMessageList = const [],
this.broadcastMessageList = const [],
});

/// Notice tab status.
final NotificationStatus noticeStatus;
/// Status.
final NotificationStatus status;

/// Personal message status.
final NotificationStatus personalMessageStatus;
/// Current loaded page number.
final int pageNumber;

/// Broadcast message status.
final NotificationStatus broadcastMessageStatus;
/// Whether has next page to load more notification.
final bool hasNextPage;

/// All fetched [Notice].
final List<Notice> noticeList;
/// All fetched notice,
final List<T> noticeList;
}

/// State of notice tab.
@MappableClass()
final class NoticeState extends NotificationBaseState<Notice>
with NoticeStateMappable {
/// Constructor.
const NoticeState({
super.status,
super.pageNumber,
super.hasNextPage,
super.noticeList,
}) : super();
}

/// All fetched [PersonalMessage].
final List<PersonalMessage> personalMessageList;
/// State of personal message tab.
@MappableClass()
final class PersonalMessageState extends NotificationBaseState<PersonalMessage>
with PersonalMessageStateMappable {
/// Constructor.
const PersonalMessageState({
super.status,
super.pageNumber,
super.hasNextPage,
super.noticeList,
}) : super();
}

/// All fetched [BroadcastMessage].
final List<BroadcastMessage> broadcastMessageList;
/// State of personal message tab.
@MappableClass()
final class BroadcastMessageState
extends NotificationBaseState<BroadcastMessage>
with BroadcastMessageStateMappable {
/// Constructor.
const BroadcastMessageState({
super.status,
super.pageNumber,
super.hasNextPage,
super.noticeList,
}) : super();
}
Loading

0 comments on commit 1d06eda

Please sign in to comment.