Skip to content

Commit

Permalink
MentionBadge FF (#2281)
Browse files Browse the repository at this point in the history
  • Loading branch information
Velin92 authored Dec 22, 2023
1 parent a960570 commit f844cd1
Show file tree
Hide file tree
Showing 20 changed files with 216 additions and 73 deletions.
2 changes: 1 addition & 1 deletion ElementX.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -6650,7 +6650,7 @@
repositoryURL = "https://github.com/matrix-org/matrix-rust-components-swift";
requirement = {
kind = exactVersion;
version = "0.0.1-december23";
version = 1.1.31;
};
};
821C67C9A7F8CC3FD41B28B4 /* XCRemoteSwiftPackageReference "emojibase-bindings" */ = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/matrix-org/matrix-rust-components-swift",
"state" : {
"revision" : "c0027815b6ac690837e4f437ae874e7a4b5bc2a7",
"version" : "0.0.1-december23"
"revision" : "c9c6725af2c9fa93c19f710e307b0b25e0f1fa26",
"version" : "1.1.31"
}
},
{
Expand Down
4 changes: 4 additions & 0 deletions ElementX/Sources/Application/AppSettings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ final class AppSettings {
case shouldCollapseRoomStateEvents
case userSuggestionsEnabled
case swiftUITimelineEnabled
case mentionsBadgeEnabled
}

private static var suiteName: String = InfoPlistReader.main.appGroupIdentifier
Expand Down Expand Up @@ -266,6 +267,9 @@ final class AppSettings {

@UserPreference(key: UserDefaultsKeys.swiftUITimelineEnabled, defaultValue: false, storageType: .volatile)
var swiftUITimelineEnabled

@UserPreference(key: UserDefaultsKeys.mentionsBadgeEnabled, defaultValue: false, storageType: .userDefaults(store))
var mentionsBadgeEnabled

#endif

Expand Down
3 changes: 3 additions & 0 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ struct HomeScreenRoom: Identifiable, Equatable {

var hasUnreads = false

var hasMentions = false

var hasOngoingCall = false

var timestamp: String?
Expand All @@ -164,6 +166,7 @@ struct HomeScreenRoom: Identifiable, Equatable {
roomId: nil,
name: "Placeholder room name",
hasUnreads: false,
hasMentions: false,
timestamp: "Now",
lastMessage: placeholderLastMessage,
isPlaceholder: true)
Expand Down
8 changes: 4 additions & 4 deletions ElementX/Sources/Screens/HomeScreen/HomeScreenViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -287,18 +287,18 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol

private func buildRoom(with details: RoomSummaryDetails, invalidated: Bool) -> HomeScreenRoom {
let identifier = invalidated ? "invalidated-" + details.id : details.id

let notificationMode = details.notificationMode == .allMessages ? nil : details.notificationMode
let hasMentions = appSettings.mentionsBadgeEnabled ? details.unreadMentionsCount > 0 : false

return HomeScreenRoom(id: identifier,
roomId: details.id,
name: details.name,
hasUnreads: details.unreadNotificationCount > 0,
hasUnreads: details.unreadMessagesCount > 0,
hasMentions: hasMentions,
hasOngoingCall: details.hasOngoingCall,
timestamp: details.lastMessageFormattedTimestamp,
lastMessage: details.lastMessage,
avatarURL: details.avatarURL,
notificationMode: notificationMode)
notificationMode: details.notificationMode)
}

private func updateVisibleRange(_ range: Range<Int>) {
Expand Down
129 changes: 85 additions & 44 deletions ElementX/Sources/Screens/HomeScreen/View/HomeScreenRoomCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ struct HomeScreenRoomCell: View {

if let timestamp = room.timestamp {
Text(timestamp)
.font(room.hasUnreads ? .compound.bodySMSemibold : .compound.bodySM)
.foregroundColor(room.hasUnreads ? .compound.textActionAccent : .compound.textSecondary)
.font(isHighlighted ? .compound.bodySMSemibold : .compound.bodySM)
.foregroundColor(isHighlighted ? .compound.textActionAccent : .compound.textSecondary)
}
}
}
Expand All @@ -119,33 +119,48 @@ struct HomeScreenRoomCell: View {
HStack(spacing: 8) {
if room.hasOngoingCall {
CompoundIcon(\.videoCallSolid, size: .xSmall, relativeTo: .compound.bodySM)
.foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary)
.foregroundColor(isHighlighted ? .compound.iconAccentTertiary : .compound.iconQuaternary)
}

if room.notificationMode == .mute {
CompoundIcon(\.notificationsSolidOff, size: .custom(15), relativeTo: .compound.bodyMD)
.accessibilityLabel(L10n.a11yNotificationsMuted)
.foregroundColor(.compound.iconQuaternary)
}

notificationModeIcon
.foregroundColor(room.hasUnreads ? .compound.iconAccentTertiary : .compound.iconQuaternary)
if room.hasMentions, room.notificationMode != .mute {
mentionIcon
.foregroundColor(.compound.iconAccentTertiary)
}

if room.hasUnreads {
if hasNewContent {
Circle()
.frame(width: 12, height: 12)
.foregroundColor(.compound.iconAccentTertiary)
.foregroundColor(isHighlighted ? .compound.iconAccentTertiary : .compound.iconQuaternary)
}
}
}
}

@ViewBuilder
private var notificationModeIcon: some View {
switch room.notificationMode {
case .none, .allMessages:
EmptyView()
case .mentionsAndKeywordsOnly:
CompoundIcon(\.mention, size: .custom(15), relativeTo: .compound.bodyMD)
.accessibilityLabel(L10n.a11yNotificationsMentionsOnly)
case .mute:
CompoundIcon(\.notificationsSolidOff, size: .custom(15), relativeTo: .compound.bodyMD)
.accessibilityLabel(L10n.a11yNotificationsMuted)
private var hasNewContent: Bool {
room.hasUnreads || room.hasMentions
}

private var isHighlighted: Bool {
guard !room.isPlaceholder else {
return false
}
return (isNotificationModeUnrestricted && hasNewContent) ||
(room.notificationMode == .mentionsAndKeywordsOnly && room.hasMentions)
}

private var isNotificationModeUnrestricted: Bool {
room.notificationMode == nil || room.notificationMode == .allMessages
}

private var mentionIcon: some View {
CompoundIcon(\.mention, size: .custom(15), relativeTo: .compound.bodyMD)
.accessibilityLabel(L10n.a11yNotificationsMentionsOnly)
}

@ViewBuilder
Expand Down Expand Up @@ -178,41 +193,67 @@ private extension View {
}

struct HomeScreenRoomCell_Previews: PreviewProvider, TestablePreview {
static var previews: some View {
let summaryProvider = MockRoomSummaryProvider(state: .loaded(.mockRooms))
static let summaryProviderGeneric = MockRoomSummaryProvider(state: .loaded(.mockRooms))
static let viewModelGeneric = {
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProviderGeneric),
mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock())

let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProvider),
return HomeScreenViewModel(userSession: userSession,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings,
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}()

static let summaryProviderForNotificationsState = MockRoomSummaryProvider(state: .loaded(.mockRoomsWithNotificationsState))
static let viewModelForNotificationsState = {
let userSession = MockUserSession(clientProxy: MockClientProxy(userID: "John Doe", roomSummaryProvider: summaryProviderForNotificationsState),
mediaProvider: MockMediaProvider(),
voiceMessageMediaManager: VoiceMessageMediaManagerMock())

let viewModel = HomeScreenViewModel(userSession: userSession,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings,
userIndicatorController: ServiceLocator.shared.userIndicatorController)
let rooms: [HomeScreenRoom] = summaryProvider.roomListPublisher.value.compactMap { summary -> HomeScreenRoom? in
switch summary {
case .empty:
return nil
case .invalidated(let details), .filled(let details):
return HomeScreenRoom(id: UUID().uuidString,
roomId: details.id,
name: details.name,
hasUnreads: details.unreadNotificationCount > 0,
hasOngoingCall: details.hasOngoingCall,
timestamp: Date(timeIntervalSinceReferenceDate: 0).formattedMinimal(),
lastMessage: details.lastMessage,
notificationMode: details.notificationMode)
}
return HomeScreenViewModel(userSession: userSession,
selectedRoomPublisher: CurrentValueSubject<String?, Never>(nil).asCurrentValuePublisher(),
appSettings: ServiceLocator.shared.settings,
userIndicatorController: ServiceLocator.shared.userIndicatorController)
}()

static func mockRoom(summary: RoomSummary) -> HomeScreenRoom? {
switch summary {
case .empty:
return nil
case .invalidated(let details), .filled(let details):
return HomeScreenRoom(id: UUID().uuidString,
roomId: details.id,
name: details.name,
hasUnreads: details.unreadMessagesCount > 0, hasMentions: details.unreadMentionsCount > 0,
hasOngoingCall: details.hasOngoingCall,
timestamp: Date(timeIntervalSinceReferenceDate: 0).formattedMinimal(),
lastMessage: details.lastMessage,
notificationMode: details.notificationMode)
}
}

static var previews: some View {
let genericRooms: [HomeScreenRoom] = summaryProviderGeneric.roomListPublisher.value.compactMap(mockRoom)

let notificationsStateRooms: [HomeScreenRoom] = summaryProviderForNotificationsState.roomListPublisher.value.compactMap(mockRoom)

return VStack(spacing: 0) {
ForEach(rooms) { room in
HomeScreenRoomCell(room: room, context: viewModel.context, isSelected: false)
VStack(spacing: 0) {
ForEach(genericRooms) { room in
HomeScreenRoomCell(room: room, context: viewModelGeneric.context, isSelected: false)
}

HomeScreenRoomCell(room: .placeholder(), context: viewModel.context, isSelected: false)
HomeScreenRoomCell(room: .placeholder(), context: viewModelGeneric.context, isSelected: false)
.redacted(reason: .placeholder)
}
.previewDisplayName("Generic")

VStack(spacing: 0) {
ForEach(notificationsStateRooms) { room in
HomeScreenRoomCell(room: room, context: viewModelForNotificationsState.context, isSelected: false)
}
}
.previewLayout(.sizeThatFits)
.previewDisplayName("Notifications State")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,8 @@ private extension InvitesScreenRoomDetails {
avatarURL: nil,
lastMessage: nil,
lastMessageFormattedTimestamp: nil,
unreadNotificationCount: 0,
unreadMessagesCount: 0,
unreadMentionsCount: 0,
notificationMode: nil,
canonicalAlias: "#footest:somewhere.org",
inviter: inviter,
Expand All @@ -206,7 +207,8 @@ private extension InvitesScreenRoomDetails {
avatarURL: avatarURL,
lastMessage: nil,
lastMessageFormattedTimestamp: nil,
unreadNotificationCount: 0,
unreadMessagesCount: 0,
unreadMentionsCount: 0,
notificationMode: nil,
canonicalAlias: alias,
inviter: inviter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ protocol DeveloperOptionsProtocol: AnyObject {
var shouldCollapseRoomStateEvents: Bool { get set }
var userSuggestionsEnabled: Bool { get set }
var swiftUITimelineEnabled: Bool { get set }
var mentionsBadgeEnabled: Bool { get set }

var elementCallBaseURL: URL { get set }
var elementCallUseEncryption: Bool { get set }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ struct DeveloperOptionsScreen: View {
}
}

Section("Mentions") {
Toggle(isOn: $context.mentionsBadgeEnabled) {
Text("Mentions badge")
Text("Requires app reboot")
}
}

Section("Element Call") {
TextField(context.elementCallBaseURL.absoluteString, text: $elementCallBaseURLString)
.submitLabel(.done)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import Foundation
import MatrixRustSDK

enum RoomNotificationModeProxy {
enum RoomNotificationModeProxy: String {
case allMessages
case mentionsAndKeywordsOnly
case mute
Expand Down
Loading

0 comments on commit f844cd1

Please sign in to comment.