mark conversation as important / unimportant

Signed-off-by: sowjanyakch <sowjanya.kch@gmail.com>
This commit is contained in:
sowjanyakch 2025-05-20 18:10:17 +02:00 committed by backportbot[bot]
parent 9247995735
commit 6707a16cda
6 changed files with 150 additions and 31 deletions

View File

@ -2,7 +2,7 @@
"formatVersion": 1, "formatVersion": 1,
"database": { "database": {
"version": 14, "version": 14,
"identityHash": "506abc931eb3b657cafe6ad1b25f635d", "identityHash": "d977dea7f7b5cc6d466a4aeb68c538fb",
"entities": [ "entities": [
{ {
"tableName": "User", "tableName": "User",
@ -122,7 +122,7 @@
}, },
{ {
"tableName": "Conversations", "tableName": "Conversations",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `objectId` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )", "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`internalId` TEXT NOT NULL, `accountId` INTEGER NOT NULL, `token` TEXT NOT NULL, `displayName` TEXT NOT NULL, `actorId` TEXT NOT NULL, `actorType` TEXT NOT NULL, `avatarVersion` TEXT NOT NULL, `callFlag` INTEGER NOT NULL, `callRecording` INTEGER NOT NULL, `callStartTime` INTEGER NOT NULL, `canDeleteConversation` INTEGER NOT NULL, `canLeaveConversation` INTEGER NOT NULL, `canStartCall` INTEGER NOT NULL, `description` TEXT NOT NULL, `hasCall` INTEGER NOT NULL, `hasPassword` INTEGER NOT NULL, `isCustomAvatar` INTEGER NOT NULL, `isFavorite` INTEGER NOT NULL, `lastActivity` INTEGER NOT NULL, `lastCommonReadMessage` INTEGER NOT NULL, `lastMessage` TEXT, `lastPing` INTEGER NOT NULL, `lastReadMessage` INTEGER NOT NULL, `lobbyState` TEXT NOT NULL, `lobbyTimer` INTEGER NOT NULL, `messageExpiration` INTEGER NOT NULL, `name` TEXT NOT NULL, `notificationCalls` INTEGER NOT NULL, `notificationLevel` TEXT NOT NULL, `objectType` TEXT NOT NULL, `objectId` TEXT NOT NULL, `participantType` TEXT NOT NULL, `permissions` INTEGER NOT NULL, `readOnly` TEXT NOT NULL, `recordingConsent` INTEGER NOT NULL, `remoteServer` TEXT, `remoteToken` TEXT, `sessionId` TEXT NOT NULL, `status` TEXT, `statusClearAt` INTEGER, `statusIcon` TEXT, `statusMessage` TEXT, `type` TEXT NOT NULL, `unreadMention` INTEGER NOT NULL, `unreadMentionDirect` INTEGER NOT NULL, `unreadMessages` INTEGER NOT NULL, `hasArchived` INTEGER NOT NULL, `hasImportant` INTEGER NOT NULL, PRIMARY KEY(`internalId`), FOREIGN KEY(`accountId`) REFERENCES `User`(`id`) ON UPDATE CASCADE ON DELETE CASCADE )",
"fields": [ "fields": [
{ {
"fieldPath": "internalId", "fieldPath": "internalId",
@ -398,6 +398,12 @@
"columnName": "hasArchived", "columnName": "hasArchived",
"affinity": "INTEGER", "affinity": "INTEGER",
"notNull": true "notNull": true
},
{
"fieldPath": "hasImportant",
"columnName": "hasImportant",
"affinity": "INTEGER",
"notNull": true
} }
], ],
"primaryKey": { "primaryKey": {
@ -713,7 +719,7 @@
], ],
"setupQueries": [ "setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '506abc931eb3b657cafe6ad1b25f635d')" "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd977dea7f7b5cc6d466a4aeb68c538fb')"
] ]
} }
} }

View File

@ -252,6 +252,8 @@ class ConversationInfoActivity :
initClearChatHistoryObserver() initClearChatHistoryObserver()
initMarkConversationAsSensitiveObserver() initMarkConversationAsSensitiveObserver()
initMarkConversationAsInsensitiveObserver() initMarkConversationAsInsensitiveObserver()
initMarkConversationAsImportantObserver()
initMarkConversationAsUnimportantObserver()
} }
private fun initMarkConversationAsSensitiveObserver() { private fun initMarkConversationAsSensitiveObserver() {
@ -381,7 +383,46 @@ class ConversationInfoActivity :
} }
} }
@SuppressLint("SetTextI18n") private fun initMarkConversationAsImportantObserver() {
viewModel.markAsImportantResult.observe(this) { uiState ->
when (uiState) {
is ConversationInfoViewModel.MarkConversationAsImportantViewState.Success -> {
binding.root,
context.getString(R.string.nc_mark_conversation_as_important),
Snackbar.LENGTH_LONG
).show()
}
is ConversationInfoViewModel.MarkConversationAsImportantViewState.Error -> {
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
Log.e(TAG, "failed to mark conversation as important", uiState.exception)
}
else -> {
}
}
}
}
private fun initMarkConversationAsUnimportantObserver() {
viewModel.markAsUnimportantResult.observe(this) { uiState ->
when (uiState) {
is ConversationInfoViewModel.MarkConversationAsUnimportantViewState.Success -> {
Snackbar.make(
binding.root,
context.getString(R.string.nc_mark_conversation_as_unimportant),
Snackbar.LENGTH_LONG
).show()
}
is ConversationInfoViewModel.MarkConversationAsUnimportantViewState.Error -> {
Snackbar.make(binding.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show()
Log.e(TAG, "failed to mark conversation as unimportant", uiState.exception)
}
else -> {
}
}
}
}
private fun initViewStateObserver() { private fun initViewStateObserver() {
viewModel.viewState.observe(this) { state -> viewModel.viewState.observe(this) { state ->
when (state) { when (state) {
@ -1025,6 +1066,29 @@ class ConversationInfoActivity :
} }
} }
binding.notificationSettingsView.importantConversationSwitch.isChecked = conversation!!.hasImportant
binding.notificationSettingsView.importantConversationSwitch.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
viewModel.markConversationAsImportant(
credentials,
conversationUser.baseUrl!!,
conversation?.token!!
)
} else {
viewModel.markConversationAsUnimportant(
credentials,
conversationUser.baseUrl!!,
conversation?.token!!
)
}
}
if (hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.IMPORTANT_CONVERSATIONS)) {
binding.notificationSettingsView.notificationSettingsImportantConversation.visibility = VISIBLE
} else {
binding.notificationSettingsView.notificationSettingsImportantConversation.visibility = GONE
}
if (!hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ARCHIVE_CONVERSATIONS)) { if (!hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ARCHIVE_CONVERSATIONS)) {
binding.archiveConversationBtn.visibility = GONE binding.archiveConversationBtn.visibility = GONE
binding.archiveConversationTextHint.visibility = GONE binding.archiveConversationTextHint.visibility = GONE
@ -1756,13 +1820,13 @@ class ConversationInfoActivity :
} }
private fun setUpNotificationSettings(module: DatabaseStorageModule) { private fun setUpNotificationSettings(module: DatabaseStorageModule) {
binding.notificationSettingsView.notificationSettingsImportantConversation.setOnClickListener { // binding.notificationSettingsView.notificationSettingsImportantConversation.setOnClickListener {
val isChecked = binding.notificationSettingsView.importantConversationSwitch.isChecked // val isChecked = binding.notificationSettingsView.importantConversationSwitch.isChecked
binding.notificationSettingsView.importantConversationSwitch.isChecked = !isChecked // binding.notificationSettingsView.importantConversationSwitch.isChecked = !isChecked
lifecycleScope.launch { // lifecycleScope.launch {
module.saveBoolean("important_conversation_switch", !isChecked) // module.saveBoolean("important_conversation_switch", !isChecked)
} // }
} // }
binding.notificationSettingsView.notificationSettingsCallNotifications.setOnClickListener { binding.notificationSettingsView.notificationSettingsCallNotifications.setOnClickListener {
val isChecked = binding.notificationSettingsView.callNotificationsSwitch.isChecked val isChecked = binding.notificationSettingsView.callNotificationsSwitch.isChecked
binding.notificationSettingsView.callNotificationsSwitch.isChecked = !isChecked binding.notificationSettingsView.callNotificationsSwitch.isChecked = !isChecked
@ -1780,8 +1844,8 @@ class ConversationInfoActivity :
} }
} }
binding.notificationSettingsView.importantConversationSwitch.isChecked = module // binding.notificationSettingsView.importantConversationSwitch.isChecked = module
.getBoolean("important_conversation_switch", false) // .getBoolean("important_conversation_switch", false)
if (conversation!!.remoteServer.isNullOrEmpty()) { if (conversation!!.remoteServer.isNullOrEmpty()) {
binding.notificationSettingsView.notificationSettingsCallNotifications.visibility = VISIBLE binding.notificationSettingsView.notificationSettingsCallNotifications.visibility = VISIBLE

View File

@ -124,6 +124,16 @@ class ConversationInfoViewModel @Inject constructor(
val getConversationReadOnlyState: LiveData<SetConversationReadOnlyViewState> val getConversationReadOnlyState: LiveData<SetConversationReadOnlyViewState>
get() = _getConversationReadOnlyState get() = _getConversationReadOnlyState
private val _markConversationAsImportantResult =
MutableLiveData<MarkConversationAsImportantViewState>(MarkConversationAsImportantViewState.None)
val markAsImportantResult: LiveData<MarkConversationAsImportantViewState>
get() = _markConversationAsImportantResult
private val _markConversationAsUnimportantResult =
MutableLiveData<MarkConversationAsUnimportantViewState>(MarkConversationAsUnimportantViewState.None)
val markAsUnimportantResult: LiveData<MarkConversationAsUnimportantViewState>
get() = _markConversationAsUnimportantResult
private val _createRoomViewState = MutableLiveData<CreateRoomUIState>(CreateRoomUIState.None) private val _createRoomViewState = MutableLiveData<CreateRoomUIState>(CreateRoomUIState.None)
val createRoomViewState: LiveData<CreateRoomUIState> val createRoomViewState: LiveData<CreateRoomUIState>
get() = _createRoomViewState get() = _createRoomViewState
@ -356,6 +366,35 @@ class ConversationInfoViewModel @Inject constructor(
conversationsRepository.unarchiveConversation(user.getCredentials(), url) conversationsRepository.unarchiveConversation(user.getCredentials(), url)
} }
@Suppress("Detekt.TooGenericExceptionCaught")
fun markConversationAsImportant(credentials: String, baseUrl: String, roomToken: String) {
viewModelScope.launch {
try {
val response = conversationsRepository.markConversationAsImportant(credentials, baseUrl, roomToken)
_markConversationAsImportantResult.value =
MarkConversationAsImportantViewState.Success(response.ocs?.meta?.statusCode!!)
} catch (exception: Exception) {
_markConversationAsImportantResult.value =
MarkConversationAsImportantViewState.Error(exception)
}
}
}
@Suppress("Detekt.TooGenericExceptionCaught")
fun markConversationAsUnimportant(credentials: String, baseUrl: String, roomToken: String) {
viewModelScope.launch {
try {
val response = conversationsRepository.markConversationAsImportant(credentials, baseUrl, roomToken)
_markConversationAsUnimportantResult.value =
MarkConversationAsUnimportantViewState.Success(response.ocs?.meta?.statusCode!!)
} catch (exception: Exception) {
_markConversationAsUnimportantResult.value =
MarkConversationAsUnimportantViewState.Error(exception)
}
}
}
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
fun clearChatHistory(apiVersion: Int, roomToken: String) { fun clearChatHistory(apiVersion: Int, roomToken: String) {
viewModelScope.launch { viewModelScope.launch {
@ -480,4 +519,16 @@ class ConversationInfoViewModel @Inject constructor(
data object Success : PasswordUiState() data object Success : PasswordUiState()
data class Error(val exception: Exception) : PasswordUiState() data class Error(val exception: Exception) : PasswordUiState()
} }
sealed class MarkConversationAsImportantViewState {
data object None : MarkConversationAsImportantViewState()
data class Success(val statusCode: Int) : MarkConversationAsImportantViewState()
data class Error(val exception: Exception) : MarkConversationAsImportantViewState()
}
sealed class MarkConversationAsUnimportantViewState {
data object None : MarkConversationAsUnimportantViewState()
data class Success(val statusCode: Int) : MarkConversationAsUnimportantViewState()
data class Error(val exception: Exception) : MarkConversationAsUnimportantViewState()
}
} }

View File

@ -65,20 +65,20 @@ class DatabaseStorageModule(conversationUser: User, conversationToken: String) {
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
suspend fun saveBoolean(key: String, value: Boolean) { suspend fun saveBoolean(key: String, value: Boolean) {
if ("call_notifications_switch" == key) { // if ("call_notifications_switch" == key) {
val apiVersion = getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4)) // val apiVersion = getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.API_V4))
val url = getUrlForRoomNotificationCalls(apiVersion, conversationUser.baseUrl, conversationToken) // val url = getUrlForRoomNotificationCalls(apiVersion, conversationUser.baseUrl, conversationToken)
val credentials = getCredentials(conversationUser.username, conversationUser.token) // val credentials = getCredentials(conversationUser.username, conversationUser.token)
val notificationLevel = if (value) 1 else 0 // val notificationLevel = if (value) 1 else 0
withContext(Dispatchers.IO) { // withContext(Dispatchers.IO) {
try { // try {
ncApiCoroutines!!.notificationCalls(credentials!!, url, notificationLevel) // ncApiCoroutines!!.notificationCalls(credentials!!, url, notificationLevel)
Log.d(TAG, "Toggled notification calls") // Log.d(TAG, "Toggled notification calls")
} catch (e: Exception) { // } catch (e: Exception) {
Log.e(TAG, "Error when trying to toggle notification calls", e) // Log.e(TAG, "Error when trying to toggle notification calls", e)
} // }
} // }
} // }
if ("lobby_switch" != key) { if ("lobby_switch" != key) {
arbitraryStorageManager!!.storeStorageSetting( arbitraryStorageManager!!.storeStorageSetting(
accountIdentifier, accountIdentifier,

View File

@ -61,8 +61,7 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/standard_margin" android:layout_marginStart="@dimen/standard_margin" />
android:clickable="false" />
</LinearLayout> </LinearLayout>

View File

@ -352,8 +352,7 @@ How to translate with transifex:
<string name="nc_sensitive_conversation">Sensitive conversation</string> <string name="nc_sensitive_conversation">Sensitive conversation</string>
<string name="nc_sensitive_conversation_hint">Message preview will be disabled in conversation list and notifications</string> <string name="nc_sensitive_conversation_hint">Message preview will be disabled in conversation list and notifications</string>
<string name="nc_important_conversation">Important conversation</string> <string name="nc_important_conversation">Important conversation</string>
<string name="nc_do_not_disturb">Ignore Do not disturb</string> <string name="nc_important_conversation_desc">\"Do not disturb\" user status is ignored for important conversations</string>
<string name="nc_important_conversation_desc">Notifications in this conversation will override Do Not Disturb settings</string>
<string name="nc_all_ok_operation">OK, all done!</string> <string name="nc_all_ok_operation">OK, all done!</string>
<string name="nc_ok">OK</string> <string name="nc_ok">OK</string>