mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-24 18:36:21 +03:00
Option to open chat without reading
Change-Id: I039bc78ef12975ebd384680f0c2634a8776e0398
This commit is contained in:
parent
7723b45993
commit
3f0920cc23
13 changed files with 65 additions and 11 deletions
|
@ -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 open rooms at first unread message instead of at the bottom of the chat
|
||||||
- Possibility to hide the voice message button in the composer
|
- Possibility to hide the voice message button in the composer
|
||||||
- Experimental feature to switch between top-level spaces by swiping the room list
|
- 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
|
- 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)
|
- Message count passed to the notification badge (visible next to the launcher icon on recent Android versions)
|
||||||
- Bigger stickers
|
- Bigger stickers
|
||||||
|
|
|
@ -57,6 +57,7 @@ data class RoomDetailViewState(
|
||||||
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
|
val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
|
||||||
val powerLevelsHelper: PowerLevelsHelper? = null,
|
val powerLevelsHelper: PowerLevelsHelper? = null,
|
||||||
val openAtFirstUnread: Boolean? = null,
|
val openAtFirstUnread: Boolean? = null,
|
||||||
|
val openAnonymously: Boolean = false,
|
||||||
val activeRoomWidgets: Async<List<Widget>> = Uninitialized,
|
val activeRoomWidgets: Async<List<Widget>> = Uninitialized,
|
||||||
val formattedTypingUsers: String? = null,
|
val formattedTypingUsers: String? = null,
|
||||||
val tombstoneEvent: Event? = null,
|
val tombstoneEvent: Event? = null,
|
||||||
|
@ -87,6 +88,7 @@ data class RoomDetailViewState(
|
||||||
// Also highlight the target event, if any
|
// Also highlight the target event, if any
|
||||||
highlightedEventId = args.eventId,
|
highlightedEventId = args.eventId,
|
||||||
openAtFirstUnread = args.openAtFirstUnread,
|
openAtFirstUnread = args.openAtFirstUnread,
|
||||||
|
openAnonymously = args.openAnonymously,
|
||||||
switchToParentSpace = args.switchToParentSpace,
|
switchToParentSpace = args.switchToParentSpace,
|
||||||
rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId
|
rootThreadEventId = args.threadTimelineArgs?.rootThreadEventId
|
||||||
)
|
)
|
||||||
|
|
|
@ -197,17 +197,17 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
if (loadRoomAtFirstUnread()) {
|
if (loadRoomAtFirstUnread()) {
|
||||||
if (vectorPreferences.readReceiptFollowsReadMarker()) {
|
if (vectorPreferences.readReceiptFollowsReadMarker()) {
|
||||||
tryOrNull { room.setMarkedUnreadFlag(false) }
|
tryOrNullAnon { room.setMarkedUnreadFlag(false) }
|
||||||
} else {
|
} else {
|
||||||
tryOrNull { room.setMarkedUnread(false) }
|
tryOrNullAnon { room.setMarkedUnread(false) }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
|
tryOrNullAnon { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Inform the SDK that the room is displayed
|
// Inform the SDK that the room is displayed
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
tryOrNull { session.onRoomDisplayed(initialState.roomId) }
|
tryOrNullAnon { session.onRoomDisplayed(initialState.roomId) }
|
||||||
}
|
}
|
||||||
callManager.addProtocolsCheckerListener(this)
|
callManager.addProtocolsCheckerListener(this)
|
||||||
callManager.checkForProtocolsSupportIfNeeded()
|
callManager.checkForProtocolsSupportIfNeeded()
|
||||||
|
@ -371,6 +371,9 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
* This is a local implementation has nothing to do with APIs
|
* This is a local implementation has nothing to do with APIs
|
||||||
*/
|
*/
|
||||||
private fun markThreadTimelineAsReadLocal() {
|
private fun markThreadTimelineAsReadLocal() {
|
||||||
|
if (initialState.openAnonymously) {
|
||||||
|
return
|
||||||
|
}
|
||||||
initialState.rootThreadEventId?.let {
|
initialState.rootThreadEventId?.let {
|
||||||
session.coroutineScope.launch {
|
session.coroutineScope.launch {
|
||||||
room.markThreadAsRead(it)
|
room.markThreadAsRead(it)
|
||||||
|
@ -658,9 +661,9 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
mostRecentDisplayedEvent?.root?.eventId?.also {
|
mostRecentDisplayedEvent?.root?.eventId?.also {
|
||||||
session.coroutineScope.launch(NonCancellable) {
|
session.coroutineScope.launch(NonCancellable) {
|
||||||
rmDimber.i{"set RM and RR to $it"}
|
rmDimber.i{"set RM and RR to $it"}
|
||||||
tryOrNull { room.setReadMarker(it) }
|
tryOrNullAnon { room.setReadMarker(it) }
|
||||||
if (loadRoomAtFirstUnread()) {
|
if (loadRoomAtFirstUnread()) {
|
||||||
tryOrNull { room.setReadReceipt(it) }
|
tryOrNullAnon { room.setReadReceipt(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -981,7 +984,7 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId ->
|
bufferedMostRecentDisplayedEvent.root.eventId?.let { eventId ->
|
||||||
session.coroutineScope.launch {
|
session.coroutineScope.launch {
|
||||||
tryOrNull { room.setReadReceipt(eventId) }
|
tryOrNullAnon { room.setReadReceipt(eventId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -998,7 +1001,7 @@ class TimelineViewModel @AssistedInject constructor(
|
||||||
private fun handleMarkAllAsRead() {
|
private fun handleMarkAllAsRead() {
|
||||||
setState { copy(unreadState = UnreadState.HasNoUnread) }
|
setState { copy(unreadState = UnreadState.HasNoUnread) }
|
||||||
viewModelScope.launch {
|
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 {
|
private fun loadRoomAtFirstUnread(): Boolean {
|
||||||
return initialState.openAtFirstUnread ?: vectorPreferences.loadRoomAtFirstUnread()
|
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 sharedData: SharedData? = null,
|
||||||
val openShareSpaceForId: String? = null,
|
val openShareSpaceForId: String? = null,
|
||||||
val openAtFirstUnread: Boolean? = null,
|
val openAtFirstUnread: Boolean? = null,
|
||||||
|
val openAnonymously: Boolean = false,
|
||||||
val threadTimelineArgs: ThreadTimelineArgs? = null,
|
val threadTimelineArgs: ThreadTimelineArgs? = null,
|
||||||
val switchToParentSpace: Boolean = false,
|
val switchToParentSpace: Boolean = false,
|
||||||
val isInviteAlreadyAccepted: Boolean = false
|
val isInviteAlreadyAccepted: Boolean = false
|
||||||
|
|
|
@ -453,6 +453,9 @@ class RoomListFragment @Inject constructor(
|
||||||
is RoomListQuickActionsSharedAction.OpenAtBottom -> {
|
is RoomListQuickActionsSharedAction.OpenAtBottom -> {
|
||||||
navigator.openRoom(requireActivity(), quickAction.roomId, openAtFirstUnread = false)
|
navigator.openRoom(requireActivity(), quickAction.roomId, openAtFirstUnread = false)
|
||||||
}
|
}
|
||||||
|
is RoomListQuickActionsSharedAction.OpenAnonymous -> {
|
||||||
|
navigator.openRoom(requireActivity(), quickAction.roomId, openAnonymously = true)
|
||||||
|
}
|
||||||
is RoomListQuickActionsSharedAction.Leave -> {
|
is RoomListQuickActionsSharedAction.Leave -> {
|
||||||
promptLeaveRoom(quickAction.roomId)
|
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()) {
|
if (vectorPreferences.loadRoomAtFirstUnread()) {
|
||||||
// TODO can we check if position of roomSummary.readMarkerId is below or equal to
|
// TODO can we check if position of roomSummary.readMarkerId is below or equal to
|
||||||
// roomSummary.latestPreviewableOriginalContentEvent, and hide this otherwise?
|
// roomSummary.latestPreviewableOriginalContentEvent, and hide this otherwise?
|
||||||
|
|
|
@ -42,6 +42,11 @@ sealed class RoomListQuickActionsSharedAction(
|
||||||
R.drawable.ic_room_actions_open_at_bottom
|
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(
|
data class NotificationsAllNoisy(val roomId: String) : RoomListQuickActionsSharedAction(
|
||||||
R.string.room_list_quick_actions_notifications_all_noisy,
|
R.string.room_list_quick_actions_notifications_all_noisy,
|
||||||
R.drawable.ic_room_actions_notifications_all_noisy
|
R.drawable.ic_room_actions_notifications_all_noisy
|
||||||
|
|
|
@ -149,13 +149,14 @@ class DefaultNavigator @Inject constructor(
|
||||||
eventId: String?,
|
eventId: String?,
|
||||||
buildTask: Boolean,
|
buildTask: Boolean,
|
||||||
isInviteAlreadyAccepted: Boolean,
|
isInviteAlreadyAccepted: Boolean,
|
||||||
openAtFirstUnread: Boolean?
|
openAtFirstUnread: Boolean?,
|
||||||
|
openAnonymously: Boolean
|
||||||
) {
|
) {
|
||||||
if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) {
|
if (sessionHolder.getSafeActiveSession()?.getRoom(roomId) == null) {
|
||||||
fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast())
|
fatalError("Trying to open an unknown room $roomId", vectorPreferences.failFast())
|
||||||
return
|
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)
|
val intent = RoomDetailActivity.newIntent(context, args)
|
||||||
startActivity(context, intent, buildTask)
|
startActivity(context, intent, buildTask)
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ interface Navigator {
|
||||||
|
|
||||||
fun softLogout(context: Context)
|
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 {
|
sealed class PostSwitchSpaceAction {
|
||||||
object None : 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_NOTIF_ONLY_ALERT_ONCE = "SETTINGS_NOTIF_ONLY_ALERT_ONCE"
|
||||||
private const val SETTINGS_HIDE_CALL_BUTTONS = "SETTINGS_HIDE_CALL_BUTTONS"
|
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_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"
|
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)
|
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
|
* 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
|
* 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_AGGREGATE_UNREAD_COUNTS, false)
|
||||||
.putBoolean(SETTINGS_ENABLE_SPACE_PAGER, true)
|
.putBoolean(SETTINGS_ENABLE_SPACE_PAGER, true)
|
||||||
.putBoolean(SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER, true)
|
.putBoolean(SETTINGS_READ_RECEIPT_FOLLOWS_READ_MARKER, true)
|
||||||
|
.putBoolean(SETTINGS_SHOW_OPEN_ANONYMOUS, true)
|
||||||
.apply()
|
.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">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="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>
|
</resources>
|
||||||
|
|
|
@ -66,6 +66,12 @@
|
||||||
android:title="@string/settings_enable_space_pager"
|
android:title="@string/settings_enable_space_pager"
|
||||||
android:summary="@string/settings_enable_space_pager_summary" />
|
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>
|
</im.vector.app.core.preference.VectorPreferenceCategory>
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue