diff --git a/vector/build.gradle b/vector/build.gradle index ba12a14a1b..c3c1d18967 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -92,7 +92,6 @@ android { debug { resValue "bool", "debug_mode", "true" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" - buildConfigField "boolean", "SHOW_HIDDEN_TIMELINE_EVENTS", "false" signingConfig signingConfigs.debug } @@ -100,7 +99,6 @@ android { release { resValue "bool", "debug_mode", "false" buildConfigField "boolean", "LOW_PRIVACY_LOG_ENABLE", "false" - buildConfigField "boolean", "SHOW_HIDDEN_TIMELINE_EVENTS", "false" minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' diff --git a/vector/src/main/java/im/vector/riotredesign/core/resources/UserPreferencesProvider.kt b/vector/src/main/java/im/vector/riotredesign/core/resources/UserPreferencesProvider.kt new file mode 100644 index 0000000000..05a4fc1bc2 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/core/resources/UserPreferencesProvider.kt @@ -0,0 +1,28 @@ +/* + * Copyright 2019 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.riotredesign.core.resources + +import android.content.Context +import im.vector.riotredesign.features.settings.PreferencesManager +import javax.inject.Inject + +class UserPreferencesProvider @Inject constructor(private val context: Context) { + + fun shouldShowHiddenEvents(): Boolean { + return PreferencesManager.shouldShowHiddenEvents(context) + } +} \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index d34df0560f..953bc0f883 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -37,6 +37,7 @@ import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.matrix.rx.rx import im.vector.riotredesign.R import im.vector.riotredesign.core.platform.VectorViewModel +import im.vector.riotredesign.core.resources.UserPreferencesProvider import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.features.command.CommandParser import im.vector.riotredesign.features.command.ParsedCommand @@ -51,6 +52,7 @@ import java.util.concurrent.TimeUnit class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: RoomDetailViewState, + userPreferencesProvider: UserPreferencesProvider, private val session: Session ) : VectorViewModel(initialState) { @@ -58,7 +60,7 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro private val roomId = initialState.roomId private val eventId = initialState.eventId private val displayedEventsObservable = BehaviorRelay.create() - private val allowedTypes = if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) { + private val allowedTypes = if (userPreferencesProvider.shouldShowHiddenEvents()) { TimelineDisplayableEvents.DEBUG_DISPLAYABLE_TYPES } else { TimelineDisplayableEvents.DISPLAYABLE_TYPES @@ -77,13 +79,9 @@ class RoomDetailViewModel @AssistedInject constructor(@Assisted initialState: Ro @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? { val fragment: RoomDetailFragment = (viewModelContext as FragmentViewModelContext).fragment() + return fragment.roomDetailViewModelFactory.create(state) } - - override fun initialState(viewModelContext: ViewModelContext): RoomDetailViewState? { - - return super.initialState(viewModelContext) - } } init { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt index afb44b6114..82e54ef9dd 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/TimelineEventController.kt @@ -30,6 +30,7 @@ import im.vector.matrix.android.api.session.room.timeline.Timeline import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.core.epoxy.LoadingItem_ import im.vector.riotredesign.core.extensions.localDateTime +import im.vector.riotredesign.core.resources.UserPreferencesProvider import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory import im.vector.riotredesign.features.home.room.detail.timeline.helper.* @@ -47,7 +48,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim private val timelineMediaSizeProvider: TimelineMediaSizeProvider, private val avatarRenderer: AvatarRenderer, @TimelineEventControllerHandler - private val backgroundHandler: Handler + private val backgroundHandler: Handler, + userPreferencesProvider: UserPreferencesProvider ) : EpoxyController(backgroundHandler, backgroundHandler), Timeline.Listener { interface Callback : ReactionPillCallback, AvatarCallback, BaseCallback, UrlClickCallback { @@ -132,6 +134,8 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim } } + private val showHiddenEvents = userPreferencesProvider.shouldShowHiddenEvents() + init { requestModelBuild() } @@ -234,7 +238,7 @@ class TimelineEventController @Inject constructor(private val dateFormatter: Tim private fun buildItemModels(currentPosition: Int, items: List): CacheItemData { val event = items[currentPosition] - val nextEvent = items.nextDisplayableEvent(currentPosition) + val nextEvent = items.nextDisplayableEvent(currentPosition, showHiddenEvents) val date = event.root.localDateTime() val nextDate = nextEvent?.root?.localDateTime() val addDaySeparator = date.toLocalDate() != nextDate?.toLocalDate() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt index 75bedd7703..32edb0b824 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/factory/TimelineItemFactory.kt @@ -17,16 +17,14 @@ package im.vector.riotredesign.features.home.room.detail.timeline.factory import im.vector.matrix.android.api.session.events.model.EventType -import im.vector.matrix.android.api.session.events.model.toModel -import im.vector.matrix.android.api.session.room.model.message.MessageContent -import im.vector.matrix.android.api.session.room.model.message.MessageDefaultContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent import im.vector.riotredesign.core.epoxy.EmptyItem_ import im.vector.riotredesign.core.epoxy.VectorEpoxyModel +import im.vector.riotredesign.features.home.AvatarRenderer import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController -import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDisplayableEvents +import im.vector.riotredesign.features.home.room.detail.timeline.helper.senderAvatar import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageInformationData -import im.vector.riotredesign.features.home.room.detail.timeline.item.MessageTextItem_ +import im.vector.riotredesign.features.home.room.detail.timeline.item.NoticeItem_ import timber.log.Timber import javax.inject.Inject @@ -34,7 +32,8 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me private val encryptionItemFactory: EncryptionItemFactory, private val encryptedItemFactory: EncryptedItemFactory, private val noticeItemFactory: NoticeItemFactory, - private val defaultItemFactory: DefaultItemFactory) { + private val defaultItemFactory: DefaultItemFactory, + private val avatarRenderer: AvatarRenderer) { fun create(event: TimelineEvent, nextEvent: TimelineEvent?, @@ -65,30 +64,21 @@ class TimelineItemFactory @Inject constructor(private val messageItemFactory: Me else -> { //These are just for debug to display hidden event, they should be filtered out in normal mode - if (TimelineDisplayableEvents.DEBUG_HIDDEN_EVENT) { - val informationData = MessageInformationData(eventId = event.root.eventId - ?: "?", - senderId = event.root.senderId ?: "", - sendState = event.sendState, - time = "", - avatarUrl = null, - memberName = "", - showInformation = false - ) - val messageContent = event.root.content.toModel() - ?: MessageDefaultContent("", "", null, null) - MessageTextItem_() - .informationData(informationData) - .message("{ \"type\": ${event.root.type} }") - .highlighted(highlight) - .longClickListener { view -> - return@longClickListener callback?.onEventLongClicked(informationData, messageContent, view) - ?: false - } - } else { - Timber.w("Ignored event (type: ${event.root.type}") - null - } + val informationData = MessageInformationData( + eventId = event.root.eventId ?: "?", + senderId = event.root.senderId ?: "", + sendState = event.sendState, + time = "", + avatarUrl = event.senderAvatar(), + memberName = "", + showInformation = false + ) + NoticeItem_() + .avatarRenderer(avatarRenderer) + .informationData(informationData) + .noticeText("{ \"type\": ${event.root.type} }") + .highlighted(highlight) + .baseCallback(callback) } } } catch (e: Exception) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt index 1523ee6a36..871edf3750 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/timeline/helper/TimelineDisplayableEvents.kt @@ -22,14 +22,10 @@ import im.vector.matrix.android.api.session.events.model.toModel import im.vector.matrix.android.api.session.room.model.RoomMember import im.vector.matrix.android.api.session.room.model.message.MessageContent import im.vector.matrix.android.api.session.room.timeline.TimelineEvent -import im.vector.riotredesign.BuildConfig import im.vector.riotredesign.core.extensions.localDateTime object TimelineDisplayableEvents { - //Debug helper, to show invisible items in time line (reaction, redacts) - val DEBUG_HIDDEN_EVENT = BuildConfig.SHOW_HIDDEN_TIMELINE_EVENTS - val DISPLAYABLE_TYPES = listOf( EventType.MESSAGE, EventType.STATE_ROOM_NAME, @@ -52,8 +48,10 @@ object TimelineDisplayableEvents { ) } -fun TimelineEvent.isDisplayable(): Boolean { - if (!TimelineDisplayableEvents.DISPLAYABLE_TYPES.contains(root.type)) { +fun TimelineEvent.isDisplayable(showHiddenEvent: Boolean): Boolean { + val allowed = TimelineDisplayableEvents.DEBUG_DISPLAYABLE_TYPES.takeIf { showHiddenEvent } + ?: TimelineDisplayableEvents.DISPLAYABLE_TYPES + if (!allowed.contains(root.type)) { return false } if (root.content.isNullOrEmpty()) { @@ -132,10 +130,10 @@ fun List.prevSameTypeEvents(index: Int, minSize: Int): List.nextDisplayableEvent(index: Int): TimelineEvent? { +fun List.nextDisplayableEvent(index: Int, showHiddenEvent: Boolean): TimelineEvent? { return if (index >= size - 1) { null } else { - subList(index + 1, this.size).firstOrNull { it.isDisplayable() } + subList(index + 1, this.size).firstOrNull { it.isDisplayable(showHiddenEvent) } } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/settings/PreferencesManager.java b/vector/src/main/java/im/vector/riotredesign/features/settings/PreferencesManager.java index d103ffb37c..89dc3bde95 100755 --- a/vector/src/main/java/im/vector/riotredesign/features/settings/PreferencesManager.java +++ b/vector/src/main/java/im/vector/riotredesign/features/settings/PreferencesManager.java @@ -155,6 +155,8 @@ public class PreferencesManager { private static final String SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY = "SETTINGS_USE_NATIVE_CAMERA_PREFERENCE_KEY"; private static final String SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY = "SETTINGS_ENABLE_SEND_VOICE_FEATURE_PREFERENCE_KEY"; + private static final String SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY = "SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY"; + // analytics public static final String SETTINGS_USE_ANALYTICS_KEY = "SETTINGS_USE_ANALYTICS_KEY"; public static final String SETTINGS_USE_RAGE_SHAKE_KEY = "SETTINGS_USE_RAGE_SHAKE_KEY"; @@ -253,6 +255,10 @@ public class PreferencesManager { .apply(); } + public static boolean shouldShowHiddenEvents(Context context) { + return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(SETTINGS_LABS_SHOW_HIDDEN_EVENTS_PREFERENCE_KEY, false); + } + /** * Tells if we have already asked the user to disable battery optimisations on android >= M devices. * diff --git a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsLabsFragment.kt index 4c9f1bee6b..f9bd57fbfb 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsLabsFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/settings/VectorSettingsLabsFragment.kt @@ -16,11 +16,6 @@ package im.vector.riotredesign.features.settings -import android.text.TextUtils -import androidx.appcompat.app.AlertDialog -import androidx.preference.Preference -import androidx.preference.PreferenceCategory -import androidx.preference.SwitchPreference import im.vector.riotredesign.R class VectorSettingsLabsFragment : VectorSettingsBaseFragment() { @@ -28,101 +23,97 @@ class VectorSettingsLabsFragment : VectorSettingsBaseFragment() { override var titleRes = R.string.room_settings_labs_pref_title override val preferenceXmlRes = R.xml.vector_settings_labs - private val mLabsCategory by lazy { - findPreference(PreferencesManager.SETTINGS_LABS_PREFERENCE_KEY) as PreferenceCategory - } - override fun bindPref() { // Lab - val useCryptoPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_PREFERENCE_KEY) as SwitchPreference - val cryptoIsEnabledPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_IS_ACTIVE_PREFERENCE_KEY) +// val useCryptoPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_PREFERENCE_KEY) as SwitchPreference +// val cryptoIsEnabledPref = findPreference(PreferencesManager.SETTINGS_ROOM_SETTINGS_LABS_END_TO_END_IS_ACTIVE_PREFERENCE_KEY) if (session.isCryptoEnabled()) { - mLabsCategory.removePreference(useCryptoPref) - - cryptoIsEnabledPref.isEnabled = false +// mLabsCategory.removePreference(useCryptoPref) +// +// cryptoIsEnabledPref.isEnabled = false } else { - mLabsCategory.removePreference(cryptoIsEnabledPref) - - useCryptoPref.isChecked = false - - useCryptoPref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValueAsVoid -> - if (TextUtils.isEmpty(session.sessionParams.credentials.deviceId)) { - activity?.let { activity -> - AlertDialog.Builder(activity) - .setMessage(R.string.room_settings_labs_end_to_end_warnings) - .setPositiveButton(R.string.logout) { _, _ -> - notImplemented() - // TODO CommonActivityUtils.logout(activity) - } - .setNegativeButton(R.string.cancel) { _, _ -> - useCryptoPref.isChecked = false - } - .setOnCancelListener { - useCryptoPref.isChecked = false - } - .show() - } - } else { - val newValue = newValueAsVoid as Boolean - - if (session.isCryptoEnabled() != newValue) { - notImplemented() - /* TODO - displayLoadingView() - - session.enableCrypto(newValue, object : MatrixCallback { - private fun refresh() { - activity?.runOnUiThread { - hideLoadingView() - useCryptoPref.isChecked = session.isCryptoEnabled - - if (session.isCryptoEnabled) { - mLabsCategory.removePreference(useCryptoPref) - mLabsCategory.addPreference(cryptoIsEnabledPref) - } - } - } - - override fun onSuccess(info: Void?) { - useCryptoPref.isEnabled = false - refresh() - } - - override fun onNetworkError(e: Exception) { - useCryptoPref.isChecked = false - } - - override fun onMatrixError(e: MatrixError) { - useCryptoPref.isChecked = false - } - - override fun onUnexpectedError(e: Exception) { - useCryptoPref.isChecked = false - } - }) - */ - } - } - - true - } +// mLabsCategory.removePreference(cryptoIsEnabledPref) +// +// useCryptoPref.isChecked = false +// +// useCryptoPref.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValueAsVoid -> +// if (TextUtils.isEmpty(mSession.sessionParams.credentials.deviceId)) { +// activity?.let { activity -> +// AlertDialog.Builder(activity) +// .setMessage(R.string.room_settings_labs_end_to_end_warnings) +// .setPositiveButton(R.string.logout) { _, _ -> +// notImplemented() +// // TODO CommonActivityUtils.logout(activity) +// } +// .setNegativeButton(R.string.cancel) { _, _ -> +// useCryptoPref.isChecked = false +// } +// .setOnCancelListener { +// useCryptoPref.isChecked = false +// } +// .show() +// } +// } else { +// val newValue = newValueAsVoid as Boolean +// +// if (mSession.isCryptoEnabled() != newValue) { +// notImplemented() +// /* TODO +// displayLoadingView() +// +// session.enableCrypto(newValue, object : MatrixCallback { +// private fun refresh() { +// activity?.runOnUiThread { +// hideLoadingView() +// useCryptoPref.isChecked = session.isCryptoEnabled +// +// if (session.isCryptoEnabled) { +// mLabsCategory.removePreference(useCryptoPref) +// mLabsCategory.addPreference(cryptoIsEnabledPref) +// } +// } +// } +// +// override fun onSuccess(info: Void?) { +// useCryptoPref.isEnabled = false +// refresh() +// } +// +// override fun onNetworkError(e: Exception) { +// useCryptoPref.isChecked = false +// } +// +// override fun onMatrixError(e: MatrixError) { +// useCryptoPref.isChecked = false +// } +// +// override fun onUnexpectedError(e: Exception) { +// useCryptoPref.isChecked = false +// } +// }) +// */ +// } +// } +// +// true +// } } // SaveMode Management - findPreference(PreferencesManager.SETTINGS_DATA_SAVE_MODE_PREFERENCE_KEY) - .onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> - notImplemented() - /* TODO - val sessions = Matrix.getMXSessions(activity) - for (session in sessions) { - session.setUseDataSaveMode(newValue as Boolean) - } - */ - - true - } +// findPreference(PreferencesManager.SETTINGS_DATA_SAVE_MODE_PREFERENCE_KEY) +// .onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> +// notImplemented() +// /* TODO +// val sessions = Matrix.getMXSessions(activity) +// for (session in sessions) { +// session.setUseDataSaveMode(newValue as Boolean) +// } +// */ +// +// true +// } } } \ No newline at end of file diff --git a/vector/src/main/res/values/strings_riotX.xml b/vector/src/main/res/values/strings_riotX.xml index a338a2075b..d93576f4ed 100644 --- a/vector/src/main/res/values/strings_riotX.xml +++ b/vector/src/main/res/values/strings_riotX.xml @@ -46,4 +46,6 @@ Thanks, the suggestion has been successfully sent The suggestion failed to be sent (%s) + Show hidden events in timeline + \ No newline at end of file diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index f6a2e35b9a..da40ddbfcd 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -3,28 +3,28 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"> - + + + + android:summary="@string/room_settings_labs_warning_message" /> - + + + - + + + + - + + + + - + + + \ No newline at end of file