Option to open chat without reading
Change-Id: I039bc78ef12975ebd384680f0c2634a8776e0398
This commit is contained in:
parent
7723b45993
commit
3f0920cc23
|
@ -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
|
||||
|
|
|
@ -57,6 +57,7 @@ data class RoomDetailViewState(
|
|||
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
|
||||
val powerLevelsHelper: PowerLevelsHelper? = null,
|
||||
val openAtFirstUnread: Boolean? = null,
|
||||
val openAnonymously: Boolean = false,
|
||||
val activeRoomWidgets: Async<List<Widget>> = 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
|
||||
)
|
||||
|
|
|
@ -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 <A>tryOrNullAnon(operation: () -> A): A? {
|
||||
if (initialState.openAnonymously) {
|
||||
return null
|
||||
}
|
||||
return tryOrNull { operation() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#000"
|
||||
android:pathData="M15.1,19.37l1,1.74c-0.96,0.44 -2.01,0.73 -3.1,0.84v-2.02C13.74,19.84 14.44,19.65 15.1,19.37zM4.07,13H2.05c0.11,1.1 0.4,2.14 0.84,3.1l1.74,-1C4.35,14.44 4.16,13.74 4.07,13zM15.1,4.63l1,-1.74C15.14,2.45 14.1,2.16 13,2.05v2.02C13.74,4.16 14.44,4.35 15.1,4.63zM19.93,11h2.02c-0.11,-1.1 -0.4,-2.14 -0.84,-3.1l-1.74,1C19.65,9.56 19.84,10.26 19.93,11zM8.9,19.37l-1,1.74c0.96,0.44 2.01,0.73 3.1,0.84v-2.02C10.26,19.84 9.56,19.65 8.9,19.37zM11,4.07V2.05c-1.1,0.11 -2.14,0.4 -3.1,0.84l1,1.74C9.56,4.35 10.26,4.16 11,4.07zM18.36,7.17l1.74,-1.01c-0.63,-0.87 -1.4,-1.64 -2.27,-2.27l-1.01,1.74C17.41,6.08 17.92,6.59 18.36,7.17zM4.63,8.9l-1.74,-1C2.45,8.86 2.16,9.9 2.05,11h2.02C4.16,10.26 4.35,9.56 4.63,8.9zM19.93,13c-0.09,0.74 -0.28,1.44 -0.56,2.1l1.74,1c0.44,-0.96 0.73,-2.01 0.84,-3.1H19.93zM16.83,18.36l1.01,1.74c0.87,-0.63 1.64,-1.4 2.27,-2.27l-1.74,-1.01C17.92,17.41 17.41,17.92 16.83,18.36zM7.17,5.64L6.17,3.89C5.29,4.53 4.53,5.29 3.9,6.17l1.74,1.01C6.08,6.59 6.59,6.08 7.17,5.64zM5.64,16.83L3.9,17.83c0.63,0.87 1.4,1.64 2.27,2.27l1.01,-1.74C6.59,17.92 6.08,17.41 5.64,16.83zM13,7h-2v5.41l4.29,4.29l1.41,-1.41L13,11.59V7z"/>
|
||||
</vector>
|
||||
|
|
@ -186,4 +186,8 @@
|
|||
|
||||
<string name="settings_read_receipt_follows_read_marker">Only mark chats as read if fully read</string>
|
||||
<string name="settings_read_receipt_follows_read_marker_summary">Do not update your read receipt when opening the room, but only gradually while reading</string>
|
||||
|
||||
<string name="room_list_quick_actions_open_anonymous">Open without reading</string>
|
||||
<string name="settings_show_open_anonymous">Open without reading</string>
|
||||
<string name="settings_show_open_anonymous_summary">Show option to open a room without automatically marking it read</string>
|
||||
</resources>
|
||||
|
|
|
@ -66,6 +66,12 @@
|
|||
android:title="@string/settings_enable_space_pager"
|
||||
android:summary="@string/settings_enable_space_pager_summary" />
|
||||
|
||||
<im.vector.app.core.preference.VectorSwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="SETTINGS_SHOW_OPEN_ANONYMOUS"
|
||||
android:title="@string/settings_show_open_anonymous"
|
||||
android:summary="@string/settings_show_open_anonymous_summary" />
|
||||
|
||||
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue