Skip to content

Commit

Permalink
feat(*): Show count of unread notices
Browse files Browse the repository at this point in the history
  • Loading branch information
realth000 committed Feb 4, 2024
1 parent 278b5f9 commit f1eceea
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 39 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
* 帖子右上角菜单 -> 倒序浏览/正序浏览。
- 新增支持从好友邀请参与话题的消息跳转到相应帖子。
- 新增支持筛选帖子。
- 在首页和我的页面内提醒有未读的消息。
* 有提醒时显示提醒数量,只有短消息时显示红点。
- 在消息提醒卡片上显示是多久以前的消息。~~终于分得清哪个是哪个了~~
- 缓存首页轮播图。

Expand All @@ -29,7 +31,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
### Changed

- 不再显示被设置为不显示的html节点。
- 尝试在首页和我的页面内提醒有未读的消息。

## [0.5.1] - 2024-01-31

Expand Down
16 changes: 13 additions & 3 deletions lib/features/homepage/bloc/homepage_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:collection/collection.dart';
import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:tsdm_client/exceptions/exceptions.dart';
import 'package:tsdm_client/extensions/string.dart';
import 'package:tsdm_client/extensions/universal_html.dart';
import 'package:tsdm_client/features/authentication/repository/authentication_repository.dart';
import 'package:tsdm_client/features/homepage/models/models.dart';
Expand Down Expand Up @@ -185,8 +186,17 @@ class HomepageBloc extends Bloc<HomepageEvent, HomepageState> {
// Style 2: With welcome text
document.querySelector('div#chart > script');

final hasUnreadNotice =
document.querySelector('a#myprompt')?.classes.contains('new') ?? false;
var hasUnreadNotice = 0;
final noticeNode = document.querySelector('a#myprompt');
if (noticeNode?.classes.contains('new') ?? false) {
hasUnreadNotice = noticeNode?.innerText
.split('(')
.lastOrNull
?.split(')')
.firstOrNull
?.parseToInt() ??
0;
}

final hasUnreadMessage =
document.querySelector('a#pm_ntc')?.classes.contains('new') ?? false;
Expand Down Expand Up @@ -288,7 +298,7 @@ class HomepageBloc extends Bloc<HomepageEvent, HomepageState> {
loggedUserInfo: loggedUserInfo,
pinnedThreadGroupList: pinnedThreadGroupList,
swiperUrlList: swiperUrlList,
hasUnreadNotice: hasUnreadNotice,
unreadNoticeCount: hasUnreadNotice,
hasUnreadMessage: hasUnreadMessage,
);
}
Expand Down
12 changes: 6 additions & 6 deletions lib/features/homepage/bloc/homepage_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ final class HomepageState extends Equatable {
this.loggedUserInfo,
this.pinnedThreadGroupList = const [],
this.swiperUrlList = const [],
this.hasUnreadNotice = false,
this.unreadNoticeCount = 0,
this.hasUnreadMessage = false,
});

Expand All @@ -65,8 +65,8 @@ final class HomepageState extends Equatable {
/// Swiper urls in the homepage.
final List<SwiperUrl> swiperUrlList;

/// Flag indicating has unread notices or not.
final bool hasUnreadNotice;
/// The count of unread notices.
final int unreadNoticeCount;

/// Flag indicating has unread messages or not.
final bool hasUnreadMessage;
Expand All @@ -79,7 +79,7 @@ final class HomepageState extends Equatable {
List<PinnedThreadGroup>? pinnedThreadGroupList,
List<SwiperUrl>? swiperUrlList,
int? documentHashCode,
bool? hasUnreadNotice,
int? unreadNoticeCount,
bool? hasUnreadMessage,
}) {
return HomepageState(
Expand All @@ -89,7 +89,7 @@ final class HomepageState extends Equatable {
pinnedThreadGroupList:
pinnedThreadGroupList ?? this.pinnedThreadGroupList,
swiperUrlList: swiperUrlList ?? this.swiperUrlList,
hasUnreadNotice: hasUnreadNotice ?? this.hasUnreadNotice,
unreadNoticeCount: unreadNoticeCount ?? this.unreadNoticeCount,
hasUnreadMessage: hasUnreadMessage ?? this.hasUnreadMessage,
);
}
Expand All @@ -101,6 +101,6 @@ final class HomepageState extends Equatable {
loggedUserInfo,
pinnedThreadGroupList,
swiperUrlList,
hasUnreadNotice,
unreadNoticeCount,
];
}
22 changes: 15 additions & 7 deletions lib/features/homepage/widgets/welcome_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,20 @@ class WelcomeSection extends StatelessWidget {
.largerOrEqualTo('homepage_welcome_expand');

final homePageState = context.read<HomepageBloc>().state;
final hasUnreadInfo =
homePageState.hasUnreadMessage || homePageState.hasUnreadNotice;
final unreadNoticeCount = homePageState.unreadNoticeCount;
final hasUnreadMessage = homePageState.hasUnreadMessage;

late final Widget noticeIcon;
if (unreadNoticeCount > 0) {
noticeIcon = Badge(
label: Text('$unreadNoticeCount'),
child: const Icon(Icons.notifications_outlined),
);
} else if (unreadNoticeCount <= 0 && hasUnreadMessage) {
noticeIcon = const Badge(child: Icon(Icons.notifications_outlined));
} else {
noticeIcon = const Icon(Icons.notifications_outlined);
}

return ConstrainedBox(
constraints: BoxConstraints(
Expand Down Expand Up @@ -208,11 +220,7 @@ class WelcomeSection extends StatelessWidget {
),
Expanded(child: Container()),
IconButton(
icon: hasUnreadInfo
? const Badge(
child: Icon(Icons.notifications_outlined),
)
: const Icon(Icons.notifications_outlined),
icon: noticeIcon,
onPressed: () async {
await context.pushNamed(ScreenPaths.notice);
},
Expand Down
29 changes: 20 additions & 9 deletions lib/features/profile/bloc/profile_bloc.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:bloc/bloc.dart';
import 'package:equatable/equatable.dart';
import 'package:tsdm_client/exceptions/exceptions.dart';
import 'package:tsdm_client/extensions/string.dart';
import 'package:tsdm_client/extensions/universal_html.dart';
import 'package:tsdm_client/features/authentication/repository/authentication_repository.dart';
import 'package:tsdm_client/features/authentication/repository/exceptions/exceptions.dart';
Expand Down Expand Up @@ -45,13 +46,13 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
event.uid == null &&
_profileRepository.hasCache()) {
final userProfile = _buildProfile(_profileRepository.getCache()!);
final (hasUnreadNotice, hasUnreadMessage) =
final (unreadNoticeCount, hasUnreadMessage) =
_buildUnreadInfoStatus(_profileRepository.getCache()!);
emit(
state.copyWith(
status: ProfileStatus.success,
userProfile: userProfile,
hasUnreadNotice: hasUnreadNotice,
unreadNoticeCount: unreadNoticeCount,
hasUnreadMessage: hasUnreadMessage,
),
);
Expand All @@ -73,13 +74,13 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(state.copyWith(status: ProfileStatus.failed));
return;
}
final (hasUnreadNotice, hasUnreadMessage) =
final (unreadNoticeCount, hasUnreadMessage) =
_buildUnreadInfoStatus(document);
emit(
state.copyWith(
status: ProfileStatus.success,
userProfile: userProfile,
hasUnreadNotice: hasUnreadNotice,
unreadNoticeCount: unreadNoticeCount,
hasUnreadMessage: hasUnreadMessage,
),
);
Expand All @@ -106,13 +107,13 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(state.copyWith(status: ProfileStatus.failed));
return;
}
final (hasUnreadNotice, hasUnreadMessage) =
final (unreadNoticeCount, hasUnreadMessage) =
_buildUnreadInfoStatus(document);
emit(
state.copyWith(
status: ProfileStatus.success,
userProfile: userProfile,
hasUnreadNotice: hasUnreadNotice,
unreadNoticeCount: unreadNoticeCount,
hasUnreadMessage: hasUnreadMessage,
),
);
Expand Down Expand Up @@ -235,12 +236,22 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
);
}

(bool hasUnreadNotice, bool hasUnreadMessage) _buildUnreadInfoStatus(
(int unreadNoticeCount, bool hasUnreadMessage) _buildUnreadInfoStatus(
uh.Document document,
) {
// Check notice status.
final hasUnreadNotice =
document.querySelector('a#myprompt')?.classes.contains('new') ?? false;
var hasUnreadNotice = 0;
final noticeNode = document.querySelector('a#myprompt');
if (noticeNode?.classes.contains('new') ?? false) {
hasUnreadNotice = noticeNode?.innerText
.split('(')
.lastOrNull
?.split(')')
.firstOrNull
?.parseToInt() ??
0;
}

final hasUnreadMessage =
document.querySelector('a#pm_ntc')?.classes.contains('new') ?? false;

Expand Down
12 changes: 6 additions & 6 deletions lib/features/profile/bloc/profile_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class ProfileState extends Equatable {
this.uid,
this.userProfile,
this.failedToLogoutReason,
this.hasUnreadNotice = false,
this.unreadNoticeCount = 0,
this.hasUnreadMessage = false,
});

Expand All @@ -52,8 +52,8 @@ class ProfileState extends Equatable {
/// page content is as same as [ProfileStatus.success].
final Exception? failedToLogoutReason;

/// Flag indicating has unread notices or not.
final bool hasUnreadNotice;
/// The mount of unread notices.
final int unreadNoticeCount;

/// Flag indicating has unread messages or not.
final bool hasUnreadMessage;
Expand All @@ -65,7 +65,7 @@ class ProfileState extends Equatable {
String? uid,
UserProfile? userProfile,
Exception? failedToLogoutReason,
bool? hasUnreadNotice,
int? unreadNoticeCount,
bool? hasUnreadMessage,
}) {
return ProfileState(
Expand All @@ -75,7 +75,7 @@ class ProfileState extends Equatable {
userProfile: userProfile ?? this.userProfile,
// This argument should be cleaned if not set.
failedToLogoutReason: failedToLogoutReason,
hasUnreadNotice: hasUnreadNotice ?? this.hasUnreadNotice,
unreadNoticeCount: unreadNoticeCount ?? this.unreadNoticeCount,
hasUnreadMessage: hasUnreadMessage ?? this.hasUnreadMessage,
);
}
Expand All @@ -87,7 +87,7 @@ class ProfileState extends Equatable {
uid,
userProfile,
failedToLogoutReason,
hasUnreadNotice,
unreadNoticeCount,
hasUnreadMessage,
];
}
22 changes: 15 additions & 7 deletions lib/features/profile/view/profile_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -122,19 +122,27 @@ class _ProfilePageState extends State<ProfilePage> {
}

final profileState = context.read<ProfileBloc>().state;
final hasUnreadInfo =
profileState.hasUnreadNotice || profileState.hasUnreadMessage;
final unreadNoticeCount = profileState.unreadNoticeCount;
final hasUnreadMessage = profileState.hasUnreadMessage;

late final Widget noticeIcon;
if (unreadNoticeCount > 0) {
noticeIcon = Badge(
label: Text('$unreadNoticeCount'),
child: const Icon(Icons.notifications_outlined),
);
} else if (unreadNoticeCount <= 0 && hasUnreadMessage) {
noticeIcon = const Badge(child: Icon(Icons.notifications_outlined));
} else {
noticeIcon = const Icon(Icons.notifications_outlined);
}

late final List<Widget> actions;
if (widget.username == null && widget.uid == null) {
// Current is current logged user's profile page.
actions = [
IconButton(
icon: hasUnreadInfo
? const Badge(
child: Icon(Icons.notifications_outlined),
)
: const Icon(Icons.notifications_outlined),
icon: noticeIcon,
onPressed: () async {
await context.pushNamed(ScreenPaths.notice);
},
Expand Down

0 comments on commit f1eceea

Please sign in to comment.