diff --git a/FEATURES.md b/FEATURES.md index 54e801813d..f70b33738a 100644 --- a/FEATURES.md +++ b/FEATURES.md @@ -19,6 +19,7 @@ Here you can find some extra features and changes compared to Element Android (w - Possibility to open rooms at first unread message instead of at the bottom of the chat - Possibility to hide the voice message button in the composer - Experimental feature to switch between top-level spaces by swiping the room list +- Option to open a room without marking anything as read automatically - Remember across app restarts which categories in the chat overview are expanded or collapsed - Message count passed to the notification badge (visible next to the launcher icon on recent Android versions) - Bigger stickers diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt index c05f263ef5..85d7f5c55c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewState.kt @@ -57,6 +57,7 @@ data class RoomDetailViewState( val asyncRoomSummary: Async = Uninitialized, val powerLevelsHelper: PowerLevelsHelper? = null, val openAtFirstUnread: Boolean? = null, + val openAnonymously: Boolean = false, val activeRoomWidgets: Async> = Uninitialized, val formattedTypingUsers: String? = null, val tombstoneEvent: Event? = null, @@ -87,6 +88,7 @@ data class RoomDetailViewState( // Also highlight the target event, if any highlightedEventId = args.eventId, openAtFirstUnread = args.openAtFirstUnread, + openAnonymously = args.openAnonymously, switchToParentSpace = args.switchToParentSpace, rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId ) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt index 9734ec6097..b37a0f08e7 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineViewModel.kt @@ -197,17 +197,17 @@ class TimelineViewModel @AssistedInject constructor( viewModelScope.launch(Dispatchers.IO) { if (loadRoomAtFirstUnread()) { if (vectorPreferences.readReceiptFollowsReadMarker()) { - tryOrNull { room.setMarkedUnreadFlag(false) } + tryOrNullAnon { room.setMarkedUnreadFlag(false) } } else { - tryOrNull { room.setMarkedUnread(false) } + tryOrNullAnon { room.setMarkedUnread(false) } } } else { - tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } + tryOrNullAnon { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) } } } // Inform the SDK that the room is displayed viewModelScope.launch(Dispatchers.IO) { - tryOrNull { session.onRoomDisplayed(initialState.roomId) } + tryOrNullAnon { session.onRoomDisplayed(initialState.roomId) } } callManager.addProtocolsCheckerListener(this) callManager.checkForProtocolsSupportIfNeeded() @@ -371,6 +371,9 @@ class TimelineViewModel @AssistedInject constructor( * This is a local implementation has nothing to do with APIs */ private fun markThreadTimelineAsReadLocal() { + if (initialState.openAnonymously) { + return + } initialState.rootThreadEventId?.let { session.coroutineScope.launch { room.markThreadAsRead(it) @@ -658,9 +661,9 @@ class TimelineViewModel @AssistedInject constructor( mostRecentDisplayedEvent?.root?.eventId?.also { session.coroutineScope.launch(NonCancellable) { rmDimber.i{"set RM and RR to $it"} - tryOrNull { room.setReadMarker(it) } + tryOrNullAnon { room.setReadMarker(it) } if (loadRoomAtFirstUnread()) { - tryOrNull { room.setReadReceipt(it) } + tryOrNullAnon { room.setReadReceipt(it) } } } } @@ -981,7 +984,7 @@ class TimelineViewModel @AssistedInject constructor( } bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId -> session.coroutineScope.launch { - tryOrNull { room.setReadReceipt(eventId) } + tryOrNullAnon { room.setReadReceipt(eventId) } } } } @@ -998,7 +1001,7 @@ class TimelineViewModel @AssistedInject constructor( private fun handleMarkAllAsRead() { setState { copy(unreadState = UnreadState.HasNoUnread) } viewModelScope.launch { - tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.BOTH) } + tryOrNullAnon { room.markAsRead(ReadService.MarkAsReadParams.BOTH) } } } @@ -1270,4 +1273,11 @@ class TimelineViewModel @AssistedInject constructor( private fun loadRoomAtFirstUnread(): Boolean { return initialState.openAtFirstUnread ?: vectorPreferences.loadRoomAtFirstUnread() } + + private inline fun tryOrNullAnon(operation: () -> A): A? { + if (initialState.openAnonymously) { + return null + } + return tryOrNull { operation() } + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/arguments/TimelineArgs.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/arguments/TimelineArgs.kt index 42c7f305c7..57dc49800c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/arguments/TimelineArgs.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/arguments/TimelineArgs.kt @@ -28,6 +28,7 @@ data class TimelineArgs( val sharedData: SharedData? = null, val openShareSpaceForId: String? = null, val openAtFirstUnread: Boolean? = null, + val openAnonymously: Boolean = false, val threadTimelineArgs: ThreadTimelineArgs? = null, val switchToParentSpace: Boolean = false, val isInviteAlreadyAccepted: Boolean = false diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 64ac1c1c48..805325d3e1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -453,6 +453,9 @@ class RoomListFragment @Inject constructor( is RoomListQuickActionsSharedAction.OpenAtBottom -> { navigator.openRoom(requireActivity(), quickAction.roomId, openAtFirstUnread = false) } + is RoomListQuickActionsSharedAction.OpenAnonymous -> { + navigator.openRoom(requireActivity(), quickAction.roomId, openAnonymously = true) + } is RoomListQuickActionsSharedAction.Leave -> { promptLeaveRoom(quickAction.roomId) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt index cee0ff2734..223a2929b9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsEpoxyController.kt @@ -76,6 +76,10 @@ class RoomListQuickActionsEpoxyController @Inject constructor( } } + if (vectorPreferences.showOpenAnonymous()) { + RoomListQuickActionsSharedAction.OpenAnonymous(roomSummary.roomId).toBottomSheetItem("action_open_anonymous") + } + if (vectorPreferences.loadRoomAtFirstUnread()) { // TODO can we check if position of roomSummary.readMarkerId is below or equal to // roomSummary.latestPreviewableOriginalContentEvent, and hide this otherwise? diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt index c66f289217..a7f1b88320 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/actions/RoomListQuickActionsSharedAction.kt @@ -42,6 +42,11 @@ sealed class RoomListQuickActionsSharedAction( R.drawable.ic_room_actions_open_at_bottom ) + data class OpenAnonymous(val roomId: String) : RoomListQuickActionsSharedAction( + R.string.room_list_quick_actions_open_anonymous, + R.drawable.ic_room_actions_open_anonymous + ) + data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction( R.string.room_list_quick_actions_notifications_all_noisy, R.drawable.ic_room_actions_notifications_all_noisy diff --git a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt index ba64e76de8..f0fc60a7e2 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/DefaultNavigator.kt @@ -149,13 +149,14 @@ class DefaultNavigator @Inject constructor( eventId: String?, buildTask: Boolean, isInviteAlreadyAccepted: Boolean, - openAtFirstUnread: Boolean? + openAtFirstUnread: Boolean?, + openAnonymously: Boolean ) { if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) { fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast()) return } - val args = TimelineArgs(roomId = roomId, eventId = eventId, isInviteAlreadyAccepted = isInviteAlreadyAccepted, openAtFirstUnread = openAtFirstUnread) + val args = TimelineArgs(roomId = roomId, eventId = eventId, isInviteAlreadyAccepted = isInviteAlreadyAccepted, openAtFirstUnread = openAtFirstUnread, openAnonymously = openAnonymously) val intent = RoomDetailActivity.newIntent(context, args) startActivity(context, intent, buildTask) } diff --git a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt index 81b39773cd..4ba1e422f7 100644 --- a/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt +++ b/vector/src/main/java/im/vector/app/features/navigation/Navigator.kt @@ -50,7 +50,7 @@ interface Navigator { fun softLogout(context: Context) - fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false, isInviteAlreadyAccepted: Boolean = false, openAtFirstUnread: Boolean? = null) + fun openRoom(context: Context, roomId: String, eventId: String? = null, buildTask: Boolean = false, isInviteAlreadyAccepted: Boolean = false, openAtFirstUnread: Boolean? = null, openAnonymously: Boolean = false) sealed class PostSwitchSpaceAction { object None : PostSwitchSpaceAction() diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index d04988a2d7..7916dbc2ac 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -218,6 +218,7 @@ class VectorPreferences @Inject constructor(private val context: Context, privat private const val SETTINGS_NOTIF_ONLY_ALERT_ONCE = "SETTINGS_NOTIF_ONLY_ALERT_ONCE" private const val SETTINGS_HIDE_CALL_BUTTONS = "SETTINGS_HIDE_CALL_BUTTONS" private const val SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER = "SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER" + private const val SETTINGS_SHOW_OPEN_ANONYMOUS = "SETTINGS_SHOW_OPEN_ANONYMOUS" private const val DID_ASK_TO_ENABLE_SESSION_PUSH = "DID_ASK_TO_ENABLE_SESSION_PUSH" @@ -1095,6 +1096,11 @@ class VectorPreferences @Inject constructor(private val context: Context, privat return defaultPrefs.getBoolean(SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER, false) } + // SC addition + fun showOpenAnonymous(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_SHOW_OPEN_ANONYMOUS, false) + } + /** * I likely do more fresh installs of the app than anyone else, so a shortcut to change some of the default settings to * my preferred values can safe me some time @@ -1119,6 +1125,7 @@ class VectorPreferences @Inject constructor(private val context: Context, privat .putBoolean(SETTINGS_AGGREGATE_UNREAD_COUNTS, false) .putBoolean(SETTINGS_ENABLE_SPACE_PAGER, true) .putBoolean(SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER, true) + .putBoolean(SETTINGS_SHOW_OPEN_ANONYMOUS, true) .apply() } diff --git a/vector/src/main/res/drawable/ic_room_actions_open_anonymous.xml b/vector/src/main/res/drawable/ic_room_actions_open_anonymous.xml new file mode 100644 index 0000000000..1510f29636 --- /dev/null +++ b/vector/src/main/res/drawable/ic_room_actions_open_anonymous.xml @@ -0,0 +1,10 @@ + + + + diff --git a/vector/src/main/res/values/strings_sc.xml b/vector/src/main/res/values/strings_sc.xml index 0025119d86..e2dfec093d 100644 --- a/vector/src/main/res/values/strings_sc.xml +++ b/vector/src/main/res/values/strings_sc.xml @@ -186,4 +186,8 @@ Only mark chats as read if fully read Do not update your read receipt when opening the room, but only gradually while reading + + Open without reading + Open without reading + Show option to open a room without automatically marking it read diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index ad53514dc8..16a7689b96 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -66,6 +66,12 @@ android:title="@string/settings_enable_space_pager" android:summary="@string/settings_enable_space_pager_summary" /> + +