diff --git a/changelog.d/5582.feature b/changelog.d/5582.feature new file mode 100644 index 0000000000..e6e72c8e9d --- /dev/null +++ b/changelog.d/5582.feature @@ -0,0 +1 @@ +Add a setting to be able to always appear offline diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt index c4bc289b75..f8472319fd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt @@ -61,10 +61,6 @@ data class MatrixConfiguration( * RoomDisplayNameFallbackProvider to provide default room display name. */ val roomDisplayNameFallbackProvider: RoomDisplayNameFallbackProvider, - /** - * True to enable presence information sync (if available). False to disable regardless of server setting. - */ - val presenceSyncEnabled: Boolean = true, /** * Thread messages default enable/disabled value */ diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/lightweight/LightweightSettingsStorage.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/lightweight/LightweightSettingsStorage.kt index 069e539e2c..90b0a57ceb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/lightweight/LightweightSettingsStorage.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/lightweight/LightweightSettingsStorage.kt @@ -20,6 +20,7 @@ import android.content.Context import androidx.core.content.edit import androidx.preference.PreferenceManager import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.internal.session.sync.SyncPresence import javax.inject.Inject /** @@ -45,7 +46,29 @@ class LightweightSettingsStorage @Inject constructor( return sdkDefaultPrefs.getBoolean(MATRIX_SDK_SETTINGS_THREAD_MESSAGES_ENABLED, matrixConfiguration.threadMessagesEnabledDefault) } + /** + * Set the presence status sent on syncs when the application is in foreground. + * + * @param presence the presence status that should be sent on sync + */ + internal fun setSyncPresenceStatus(presence: SyncPresence) { + sdkDefaultPrefs.edit { + putString(MATRIX_SDK_SETTINGS_FOREGROUND_PRESENCE_STATUS, presence.value) + } + } + + /** + * Get the presence status that should be sent on syncs when the application is in foreground. + * + * @return the presence status that should be sent on sync + */ + internal fun getSyncPresenceStatus(): SyncPresence { + val presenceString = sdkDefaultPrefs.getString(MATRIX_SDK_SETTINGS_FOREGROUND_PRESENCE_STATUS, SyncPresence.Online.value) + return SyncPresence.from(presenceString) ?: SyncPresence.Online + } + companion object { const val MATRIX_SDK_SETTINGS_THREAD_MESSAGES_ENABLED = "MATRIX_SDK_SETTINGS_THREAD_MESSAGES_ENABLED" + private const val MATRIX_SDK_SETTINGS_FOREGROUND_PRESENCE_STATUS = "MATRIX_SDK_SETTINGS_FOREGROUND_PRESENCE_STATUS" } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/service/DefaultPresenceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/service/DefaultPresenceService.kt index 1083d5b4c2..d74251ae96 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/service/DefaultPresenceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/presence/service/DefaultPresenceService.kt @@ -20,18 +20,22 @@ package org.matrix.android.sdk.internal.session.presence.service import org.matrix.android.sdk.api.session.presence.PresenceService import org.matrix.android.sdk.api.session.presence.model.PresenceEnum import org.matrix.android.sdk.api.session.presence.model.UserPresence +import org.matrix.android.sdk.internal.database.lightweight.LightweightSettingsStorage import org.matrix.android.sdk.internal.di.UserId import org.matrix.android.sdk.internal.session.presence.service.task.GetPresenceTask import org.matrix.android.sdk.internal.session.presence.service.task.SetPresenceTask +import org.matrix.android.sdk.internal.session.sync.SyncPresence import javax.inject.Inject internal class DefaultPresenceService @Inject constructor( @UserId private val userId: String, private val setPresenceTask: SetPresenceTask, - private val getPresenceTask: GetPresenceTask + private val getPresenceTask: GetPresenceTask, + private val lightweightSettingsStorage: LightweightSettingsStorage ) : PresenceService { override suspend fun setMyPresence(presence: PresenceEnum, statusMsg: String?) { + lightweightSettingsStorage.setSyncPresenceStatus(SyncPresence.from(presence)) setPresenceTask.execute(SetPresenceTask.Params(userId, presence, statusMsg)) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt index 18e17c7d13..c67cc54b75 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/SyncPresence.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.internal.session.sync +import org.matrix.android.sdk.api.session.presence.model.PresenceEnum + /** * For `set_presence` parameter in the /sync request * @@ -27,5 +29,16 @@ package org.matrix.android.sdk.internal.session.sync enum class SyncPresence(val value: String) { Offline("offline"), Online("online"), - Unavailable("unavailable") + Unavailable("unavailable"); + + companion object { + fun from(presenceEnum: PresenceEnum): SyncPresence { + return when (presenceEnum) { + PresenceEnum.ONLINE -> Online + PresenceEnum.OFFLINE -> Offline + PresenceEnum.UNAVAILABLE -> Unavailable + } + } + fun from(s: String?): SyncPresence? = values().find { it.value == s } + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt index e5bed12181..6a7af1dda4 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/handler/PresenceSyncHandler.kt @@ -31,26 +31,24 @@ import javax.inject.Inject internal class PresenceSyncHandler @Inject constructor(private val matrixConfiguration: MatrixConfiguration) { fun handle(realm: Realm, presenceSyncResponse: PresenceSyncResponse?) { - if (matrixConfiguration.presenceSyncEnabled) { - presenceSyncResponse?.events - ?.filter { event -> event.type == EventType.PRESENCE } - ?.forEach { event -> - val content = event.getPresenceContent() ?: return@forEach - val userId = event.senderId ?: return@forEach - val userPresenceEntity = UserPresenceEntity( - userId = userId, - lastActiveAgo = content.lastActiveAgo, - statusMessage = content.statusMessage, - isCurrentlyActive = content.isCurrentlyActive, - avatarUrl = content.avatarUrl, - displayName = content.displayName - ).also { - it.presence = content.presence - } - - storePresenceToDB(realm, userPresenceEntity) + presenceSyncResponse?.events + ?.filter { event -> event.type == EventType.PRESENCE } + ?.forEach { event -> + val content = event.getPresenceContent() ?: return@forEach + val userId = event.senderId ?: return@forEach + val userPresenceEntity = UserPresenceEntity( + userId = userId, + lastActiveAgo = content.lastActiveAgo, + statusMessage = content.statusMessage, + isCurrentlyActive = content.isCurrentlyActive, + avatarUrl = content.avatarUrl, + displayName = content.displayName + ).also { + it.presence = content.presence } - } + + storePresenceToDB(realm, userPresenceEntity) + } } /** diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt index 50049dacab..da49098413 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt @@ -37,9 +37,9 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.sync.SyncState import org.matrix.android.sdk.api.session.sync.model.SyncResponse +import org.matrix.android.sdk.internal.database.lightweight.LightweightSettingsStorage import org.matrix.android.sdk.internal.network.NetworkConnectivityChecker import org.matrix.android.sdk.internal.session.call.ActiveCallHandler -import org.matrix.android.sdk.internal.session.sync.SyncPresence import org.matrix.android.sdk.internal.session.sync.SyncTask import org.matrix.android.sdk.internal.util.BackgroundDetectionObserver import org.matrix.android.sdk.internal.util.Debouncer @@ -59,7 +59,8 @@ private val loggerTag = LoggerTag("SyncThread", LoggerTag.SYNC) internal class SyncThread @Inject constructor(private val syncTask: SyncTask, private val networkConnectivityChecker: NetworkConnectivityChecker, private val backgroundDetectionObserver: BackgroundDetectionObserver, - private val activeCallHandler: ActiveCallHandler + private val activeCallHandler: ActiveCallHandler, + private val lightweightSettingsStorage: LightweightSettingsStorage ) : Thread("SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { private var state: SyncState = SyncState.Idle @@ -182,7 +183,8 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask, else -> DEFAULT_LONG_POOL_TIMEOUT } Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout") - val params = SyncTask.Params(timeout, SyncPresence.Online, afterPause = afterPause) + val presence = lightweightSettingsStorage.getSyncPresenceStatus() + val params = SyncTask.Params(timeout, presence, afterPause = afterPause) val sync = syncScope.launch { previousSyncResponseHasToDevice = doSync(params) } diff --git a/vector-config/src/main/res/values/config-settings.xml b/vector-config/src/main/res/values/config-settings.xml index 40fc68bbae..b6d1c6676c 100755 --- a/vector-config/src/main/res/values/config-settings.xml +++ b/vector-config/src/main/res/values/config-settings.xml @@ -28,6 +28,8 @@ true false + false + false diff --git a/vector/build.gradle b/vector/build.gradle index de0b08d632..52132ee074 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -151,7 +151,6 @@ android { buildConfigField "Boolean", "enableLocationSharing", "true" buildConfigField "String", "mapTilerKey", "\"fU3vlMsMn4Jb6dnEIFsx\"" - buildConfigField "Boolean", "PRESENCE_SYNC_ENABLED", "true" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index fdd6e3c2ba..5eaa35c5c7 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -121,7 +121,6 @@ object VectorStaticModule { applicationFlavor = BuildConfig.FLAVOR_DESCRIPTION, roomDisplayNameFallbackProvider = vectorRoomDisplayNameFallbackProvider, threadMessagesEnabledDefault = vectorPreferences.areThreadMessagesEnabled(), - presenceSyncEnabled = BuildConfig.PRESENCE_SYNC_ENABLED ) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index c32657e45b..8a90295967 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -210,7 +210,6 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.billcarsonfr.jsonviewer.JSonViewerDialog import org.commonmark.parser.Parser -import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.content.ContentAttachmentData import org.matrix.android.sdk.api.session.events.model.EventType @@ -266,8 +265,7 @@ class TimelineFragment @Inject constructor( private val pillsPostProcessorFactory: PillsPostProcessor.Factory, private val callManager: WebRtcCallManager, private val audioMessagePlaybackTracker: AudioMessagePlaybackTracker, - private val clock: Clock, - private val matrixConfiguration: MatrixConfiguration + private val clock: Clock ) : VectorBaseFragment(), TimelineEventController.Callback, @@ -1650,7 +1648,7 @@ class TimelineFragment @Inject constructor( views.includeRoomToolbar.roomToolbarContentView.isClickable = roomSummary.membership == Membership.JOIN views.includeRoomToolbar.roomToolbarTitleView.text = roomSummary.displayName avatarRenderer.render(roomSummary.toMatrixItem(), views.includeRoomToolbar.roomToolbarAvatarImageView) - val showPresence = roomSummary.isDirect && matrixConfiguration.presenceSyncEnabled + val showPresence = roomSummary.isDirect views.includeRoomToolbar.roomToolbarPresenceImageView.render(showPresence, roomSummary.directUserPresence) val shieldView = if (showPresence) views.includeRoomToolbar.roomToolbarTitleShield else views.includeRoomToolbar.roomToolbarAvatarShield shieldView.render(roomSummary.roomEncryptionTrustLevel) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt index ca2a747b3b..6326d9c97a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomSummaryItemFactory.kt @@ -29,7 +29,6 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.timeline.format.DisplayableEventFormatter import im.vector.app.features.home.room.typing.TypingHelper import im.vector.lib.core.utils.epoxy.charsequence.toEpoxyCharSequence -import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -42,8 +41,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor private val stringProvider: StringProvider, private val typingHelper: TypingHelper, private val avatarRenderer: AvatarRenderer, - private val errorFormatter: ErrorFormatter, - private val matrixConfiguration: MatrixConfiguration) { + private val errorFormatter: ErrorFormatter) { fun create(roomSummary: RoomSummary, roomChangeMembershipStates: Map, @@ -127,7 +125,7 @@ class RoomSummaryItemFactory @Inject constructor(private val displayableEventFor // We do not display shield in the room list anymore // .encryptionTrustLevel(roomSummary.roomEncryptionTrustLevel) .izPublic(roomSummary.isPublic) - .showPresence(roomSummary.isDirect && matrixConfiguration.presenceSyncEnabled) + .showPresence(roomSummary.isDirect) .userPresence(roomSummary.directUserPresence) .matrixItem(roomSummary.toMatrixItem()) .lastEventTime(latestEventTime) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index 9177f843a0..3944066584 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -54,7 +54,6 @@ import im.vector.app.features.home.room.list.actions.RoomListQuickActionsSharedA import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.parcelize.Parcelize -import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.session.room.notification.RoomNotificationState import org.matrix.android.sdk.api.util.toMatrixItem import timber.log.Timber @@ -69,7 +68,6 @@ class RoomProfileFragment @Inject constructor( private val roomProfileController: RoomProfileController, private val avatarRenderer: AvatarRenderer, private val roomDetailPendingActionStore: RoomDetailPendingActionStore, - private val matrixConfiguration: MatrixConfiguration ) : VectorBaseFragment(), RoomProfileController.Callback { @@ -224,7 +222,7 @@ class RoomProfileFragment @Inject constructor( avatarRenderer.render(matrixItem, views.matrixProfileToolbarAvatarImageView) headerViews.roomProfileDecorationImageView.render(it.roomEncryptionTrustLevel) views.matrixProfileDecorationToolbarAvatarImageView.render(it.roomEncryptionTrustLevel) - headerViews.roomProfilePresenceImageView.render(it.isDirect && matrixConfiguration.presenceSyncEnabled, it.directUserPresence) + headerViews.roomProfilePresenceImageView.render(it.isDirect, it.directUserPresence) headerViews.roomProfilePublicImageView.isVisible = it.isPublic && !it.isDirect } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt index 6e0bb12642..07236fb397 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/members/RoomMemberListController.kt @@ -27,7 +27,6 @@ import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.AvatarRenderer import me.gujun.android.span.span -import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.session.events.model.Event import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.api.session.room.model.RoomMemberSummary @@ -40,8 +39,7 @@ class RoomMemberListController @Inject constructor( private val avatarRenderer: AvatarRenderer, private val stringProvider: StringProvider, private val colorProvider: ColorProvider, - private val roomMemberSummaryFilter: RoomMemberSummaryFilter, - private val matrixConfiguration: MatrixConfiguration + private val roomMemberSummaryFilter: RoomMemberSummaryFilter ) : TypedEpoxyController() { interface Callback { @@ -124,7 +122,6 @@ class RoomMemberListController @Inject constructor( host: RoomMemberListController, data: RoomMemberListViewState) { val powerLabel = stringProvider.getString(powerLevelCategory.titleRes) - val presenceSyncEnabled = matrixConfiguration.presenceSyncEnabled profileMatrixItemWithPowerLevelWithPresence { id(roomMember.userId) @@ -134,7 +131,7 @@ class RoomMemberListController @Inject constructor( clickListener { host.callback?.onRoomMemberClicked(roomMember) } - showPresence(presenceSyncEnabled) + showPresence(true) userPresence(roomMember.userPresence) powerLevelLabel( span { 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 74fcc0be5d..195072465b 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 @@ -100,6 +100,7 @@ class VectorPreferences @Inject constructor(private val context: Context) { private const val SETTINGS_ENABLE_CHAT_EFFECTS = "SETTINGS_ENABLE_CHAT_EFFECTS" private const val SETTINGS_SHOW_EMOJI_KEYBOARD = "SETTINGS_SHOW_EMOJI_KEYBOARD" private const val SETTINGS_LABS_ENABLE_LATEX_MATHS = "SETTINGS_LABS_ENABLE_LATEX_MATHS" + const val SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE = "SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE" // Room directory private const val SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS = "SETTINGS_ROOM_DIRECTORY_SHOW_ALL_PUBLIC_ROOMS" @@ -865,6 +866,16 @@ class VectorPreferences @Inject constructor(private val context: Context) { return defaultPrefs.getBoolean(SETTINGS_INTERFACE_BUBBLE_KEY, getDefault(R.bool.settings_interface_bubble_default)) } + /** + * Tells if user should always appear offline or not. + * + * @return true if user should always appear offline + */ + fun userAlwaysAppearsOffline(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE, + getDefault(R.bool.settings_presence_user_always_appears_offline_default)) + } + /** * Update the rage shake enabled status. * diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt index 0c7b1bd7d9..155234a172 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt @@ -21,6 +21,7 @@ import android.content.Context import android.os.Bundle import android.widget.CheckedTextView import androidx.core.view.children +import androidx.lifecycle.lifecycleScope import androidx.preference.Preference import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.BuildConfig @@ -36,6 +37,8 @@ import im.vector.app.features.MainActivityArgs import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.themes.ThemeUtils +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.presence.model.PresenceEnum import javax.inject.Inject class VectorSettingsPreferencesFragment @Inject constructor( @@ -78,6 +81,17 @@ class VectorSettingsPreferencesFragment @Inject constructor( } } + findPreference(VectorPreferences.SETTINGS_PRESENCE_USER_ALWAYS_APPEARS_OFFLINE)!!.let { pref -> + pref.isChecked = vectorPreferences.userAlwaysAppearsOffline() + pref.setOnPreferenceChangeListener { _, newValue -> + val presenceOfflineModeEnabled = newValue as? Boolean ?: false + lifecycleScope.launch { + session.setMyPresence(if (presenceOfflineModeEnabled) PresenceEnum.OFFLINE else PresenceEnum.ONLINE) + } + true + } + } + findPreference(VectorPreferences.SETTINGS_PREF_SPACE_SHOW_ALL_ROOM_IN_HOME)!!.let { pref -> pref.isChecked = vectorPreferences.prefSpacesShowAllRoomInHome() pref.setOnPreferenceChangeListener { _, _ -> diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 8cbd42c578..b39870832d 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -1056,6 +1056,11 @@ 1 month Forever + + Presence + Offline mode + If enabled, you will always appear offline to other users, even when using the application. + diff --git a/vector/src/main/res/xml/vector_settings_preferences.xml b/vector/src/main/res/xml/vector_settings_preferences.xml index 78bd64111c..6c8250a76a 100644 --- a/vector/src/main/res/xml/vector_settings_preferences.xml +++ b/vector/src/main/res/xml/vector_settings_preferences.xml @@ -198,6 +198,18 @@ + + + + + +