diff --git a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json index 6fa34ab2e..a655cd9f7 100644 --- a/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json +++ b/app/schemas/com.nextcloud.talk.data.source.local.TalkDatabase/11.json @@ -2,7 +2,7 @@ "formatVersion": 1, "database": { "version": 11, - "identityHash": "bc802cadfdef41d3eb94ffbb0729eb89", + "identityHash": "7edb537b6987d0de6586a6760c970958", "entities": [ { "tableName": "User", @@ -138,7 +138,7 @@ }, { "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, `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, 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, `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 )", "fields": [ { "fieldPath": "internalId", @@ -409,6 +409,12 @@ "columnName": "unreadMessages", "affinity": "INTEGER", "notNull": true + }, + { + "fieldPath": "hasArchived", + "columnName": "hasArchived", + "affinity": "INTEGER", + "notNull": true } ], "primaryKey": { @@ -713,7 +719,7 @@ "views": [], "setupQueries": [ "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, 'bc802cadfdef41d3eb94ffbb0729eb89')" + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7edb537b6987d0de6586a6760c970958')" ] } } \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt index 537bdeb14..8d399f1ec 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt +++ b/app/src/main/java/com/nextcloud/talk/api/NcApiCoroutines.kt @@ -110,4 +110,10 @@ interface NcApiCoroutines { @DELETE suspend fun deleteConversationAvatar(@Header("Authorization") authorization: String, @Url url: String): RoomOverall + + @POST + suspend fun archiveConversation(@Header("Authorization") authorization: String, @Url url: String): GenericOverall + + @DELETE + suspend fun unarchiveConversation(@Header("Authorization") authorization: String, @Url url: String): GenericOverall } diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt index 3b8837f5a..6381194a0 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/ConversationInfoActivity.kt @@ -22,8 +22,10 @@ import android.view.View import android.view.View.GONE import android.view.View.VISIBLE import androidx.appcompat.app.AlertDialog +import androidx.core.content.res.ResourcesCompat import androidx.fragment.app.FragmentTransaction import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.lifecycleScope import androidx.work.Data import androidx.work.OneTimeWorkRequest import androidx.work.WorkManager @@ -86,6 +88,7 @@ import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers +import kotlinx.coroutines.launch import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode import java.util.Calendar @@ -756,6 +759,40 @@ class ConversationInfoActivity : } } + if (!CapabilitiesUtil.isArchiveConversationsAvailable(spreedCapabilities)) { + binding.archiveConversationBtn.visibility = GONE + } + + binding.archiveConversationBtn.setOnClickListener { + this.lifecycleScope.launch { + if (conversation!!.hasArchived) { + viewModel.unarchiveConversation(conversationUser, conversationToken) + binding.archiveConversationIcon + .setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.outline_archive_24, null)) + binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) + binding.archiveConversationTextHint.text = resources.getString(R.string.archive_hint) + } else { + viewModel.archiveConversation(conversationUser, conversationToken) + binding.archiveConversationIcon + .setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_eye, null)) + binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) + binding.archiveConversationTextHint.text = resources.getString(R.string.unarchive_hint) + } + } + } + + if (conversation!!.hasArchived) { + binding.archiveConversationIcon + .setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.ic_eye, null)) + binding.archiveConversationText.text = resources.getString(R.string.unarchive_conversation) + binding.archiveConversationTextHint.text = resources.getString(R.string.unarchive_hint) + } else { + binding.archiveConversationIcon + .setImageDrawable(ResourcesCompat.getDrawable(resources, R.drawable.outline_archive_24, null)) + binding.archiveConversationText.text = resources.getString(R.string.archive_conversation) + binding.archiveConversationTextHint.text = resources.getString(R.string.archive_hint) + } + if (!isDestroyed) { binding.dangerZoneOptions.visibility = VISIBLE diff --git a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt index 3a145beeb..a84fd4da8 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationinfo/viewmodel/ConversationInfoViewModel.kt @@ -18,6 +18,7 @@ import com.nextcloud.talk.models.domain.ConversationModel import com.nextcloud.talk.models.json.capabilities.SpreedCapability import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.models.json.participants.TalkBan +import com.nextcloud.talk.repositories.conversations.ConversationsRepository import com.nextcloud.talk.utils.ApiUtils import io.reactivex.Observer import io.reactivex.android.schedulers.AndroidSchedulers @@ -26,7 +27,8 @@ import io.reactivex.schedulers.Schedulers import javax.inject.Inject class ConversationInfoViewModel @Inject constructor( - private val chatNetworkDataSource: ChatNetworkDataSource + private val chatNetworkDataSource: ChatNetworkDataSource, + private val conversationsRepository: ConversationsRepository ) : ViewModel() { object LifeCycleObserver : DefaultLifecycleObserver { @@ -200,6 +202,18 @@ class ConversationInfoViewModel @Inject constructor( }) } + suspend fun archiveConversation(user: User, token: String) { + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) + val url = ApiUtils.getUrlForArchive(apiVersion, user.baseUrl, token) + conversationsRepository.archiveConversation(user.getCredentials(), url) + } + + suspend fun unarchiveConversation(user: User, token: String) { + val apiVersion = ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4, ApiUtils.API_V1)) + val url = ApiUtils.getUrlForArchive(apiVersion, user.baseUrl, token) + conversationsRepository.unarchiveConversation(user.getCredentials(), url) + } + inner class GetRoomObserver : Observer { override fun onSubscribe(d: Disposable) { // unused atm diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index e3a367f0c..3a13a7f3f 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -210,7 +210,9 @@ class ConversationsListActivity : private var filterState = mutableMapOf( FilterConversationFragment.MENTION to false, - FilterConversationFragment.UNREAD to false + FilterConversationFragment.UNREAD to false, + FilterConversationFragment.ARCHIVE to false, + FilterConversationFragment.DEFAULT to true ) val searchBehaviorSubject = BehaviorSubject.createDefault(false) private lateinit var accountIconBadge: BadgeDrawable @@ -380,7 +382,7 @@ class ConversationsListActivity : sortConversations(conversationItemsWithHeader) // Filter Conversations - if (!filterState.containsValue(true)) filterableConversationItems = conversationItems + if (!hasFilterEnabled()) filterableConversationItems = conversationItems filterConversation() adapter!!.updateDataSet(filterableConversationItems, false) Handler().postDelayed({ checkToShowUnreadBubble() }, UNREAD_BUBBLE_DELAY.toLong()) @@ -395,6 +397,14 @@ class ConversationsListActivity : } } + private fun hasFilterEnabled(): Boolean { + for ((k, v) in filterState) { + if (k != FilterConversationFragment.DEFAULT && v) return true + } + + return false + } + fun filterConversation() { val accountId = UserIdUtils.getIdForUser(userManager.currentUser.blockingGet()) filterState[FilterConversationFragment.UNREAD] = ( @@ -413,22 +423,24 @@ class ConversationsListActivity : ).blockingGet()?.value ?: "" ) == "true" + filterState[FilterConversationFragment.ARCHIVE] = ( + arbitraryStorageManager.getStorageSetting( + accountId, + FilterConversationFragment.ARCHIVE, + "" + ).blockingGet()?.value ?: "" + ) == "true" + val newItems: MutableList> = ArrayList() - if (filterState[FilterConversationFragment.UNREAD] == false && - filterState[FilterConversationFragment.MENTION] == false - ) { - adapter!!.updateDataSet(conversationItems, true) - } else { - val items = conversationItems - for (i in items) { - val conversation = (i as ConversationItem).model - if (filter(conversation)) { - newItems.add(i) - } + val items = conversationItems + for (i in items) { + val conversation = (i as ConversationItem).model + if (filter(conversation)) { + newItems.add(i) } - adapter!!.updateDataSet(newItems, true) - setFilterableItems(newItems) } + adapter!!.updateDataSet(newItems, true) + setFilterableItems(newItems) updateFilterConversationButtonColor() } @@ -449,10 +461,19 @@ class ConversationsListActivity : ) FilterConversationFragment.UNREAD -> result = result && (conversation.unreadMessages > 0) + + FilterConversationFragment.DEFAULT -> { + result = if (filterState[FilterConversationFragment.ARCHIVE] == true) { + result && conversation.hasArchived + } else { + result && !conversation.hasArchived + } + } } } } + Log.d(TAG, "Conversation: ${conversation.name} Result: $result") return result } @@ -649,7 +670,7 @@ class ConversationsListActivity : override fun onMenuItemActionExpand(item: MenuItem): Boolean { initSearchDisposable() adapter!!.setHeadersShown(true) - if (!filterState.containsValue(true)) filterableConversationItems = searchableConversationItems + if (!hasFilterEnabled()) filterableConversationItems = searchableConversationItems adapter!!.updateDataSet(filterableConversationItems, false) adapter!!.showAllHeaders() binding.swipeRefreshLayoutView?.isEnabled = false @@ -659,7 +680,7 @@ class ConversationsListActivity : override fun onMenuItemActionCollapse(item: MenuItem): Boolean { adapter!!.setHeadersShown(false) - if (!filterState.containsValue(true)) filterableConversationItems = conversationItemsWithHeader + if (!hasFilterEnabled()) filterableConversationItems = conversationItemsWithHeader adapter!!.updateDataSet(filterableConversationItems, false) adapter!!.hideAllHeaders() if (searchHelper != null) { @@ -1826,7 +1847,7 @@ class ConversationsListActivity : } fun updateFilterConversationButtonColor() { - if (filterState.containsValue(true)) { + if (hasFilterEnabled()) { binding.filterConversationsButton.let { viewThemeUtils.platform.colorImageView(it, ColorRole.PRIMARY) } } else { binding.filterConversationsButton.let { diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt index f00c502ba..1926cbf0e 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/RepositoryModule.kt @@ -70,8 +70,12 @@ import okhttp3.OkHttpClient class RepositoryModule { @Provides - fun provideConversationsRepository(ncApi: NcApi, userProvider: CurrentUserProviderNew): ConversationsRepository { - return ConversationsRepositoryImpl(ncApi, userProvider) + fun provideConversationsRepository( + ncApi: NcApi, + ncApiCoroutines: NcApiCoroutines, + userProvider: CurrentUserProviderNew + ): ConversationsRepository { + return ConversationsRepositoryImpl(ncApi, ncApiCoroutines, userProvider) } @Provides diff --git a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt index c6c80a485..90acf6117 100644 --- a/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/data/database/mappers/ConversationMapUtils.kt @@ -59,7 +59,8 @@ fun ConversationModel.asEntity() = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) fun ConversationEntity.asModel() = @@ -109,7 +110,8 @@ fun ConversationEntity.asModel() = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) fun Conversation.asEntity(accountId: Long) = @@ -158,5 +160,6 @@ fun Conversation.asEntity(accountId: Long) = callStartTime = callStartTime, recordingConsentRequired = recordingConsentRequired, remoteServer = remoteServer, - remoteToken = remoteToken + remoteToken = remoteToken, + hasArchived = hasArchived ) diff --git a/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt b/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt index 1c0d067de..4f4652264 100644 --- a/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt +++ b/app/src/main/java/com/nextcloud/talk/data/database/model/ConversationEntity.kt @@ -92,7 +92,8 @@ data class ConversationEntity( @ColumnInfo(name = "type") var type: ConversationEnums.ConversationType, @ColumnInfo(name = "unreadMention") var unreadMention: Boolean = false, @ColumnInfo(name = "unreadMentionDirect") var unreadMentionDirect: Boolean, - @ColumnInfo(name = "unreadMessages") var unreadMessages: Int = 0 + @ColumnInfo(name = "unreadMessages") var unreadMessages: Int = 0, + @ColumnInfo(name = "hasArchived") var hasArchived: Boolean = false // missing/not needed: attendeeId // missing/not needed: attendeePin // missing/not needed: attendeePermissions diff --git a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt index 0d357b430..e255357cb 100644 --- a/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt +++ b/app/src/main/java/com/nextcloud/talk/data/source/local/Migrations.kt @@ -9,6 +9,7 @@ package com.nextcloud.talk.data.source.local import android.util.Log import androidx.room.migration.Migration import androidx.sqlite.db.SupportSQLiteDatabase +import java.sql.SQLException @Suppress("MagicNumber") object Migrations { @@ -40,6 +41,13 @@ object Migrations { } } + val MIGRATION_11_12 = object : Migration(11, 12) { + override fun migrate(db: SupportSQLiteDatabase) { + Log.i("Migrations", "Migrating 11 to 12") + addArchiveConversations(db) + } + } + fun migrateToRoom(db: SupportSQLiteDatabase) { db.execSQL( "CREATE TABLE User_new (" + @@ -237,4 +245,15 @@ object Migrations { "ON `ChatBlocks` (`internalConversationId`)" ) } + + fun addArchiveConversations(db: SupportSQLiteDatabase) { + try { + db.execSQL( + "ALTER TABLE Conversations " + + "ADD `hasArchived` INTEGER;" + ) + } catch (e: SQLException) { + Log.i("Migrations", "hasArchived already exists") + } + } } diff --git a/app/src/main/java/com/nextcloud/talk/data/source/local/TalkDatabase.kt b/app/src/main/java/com/nextcloud/talk/data/source/local/TalkDatabase.kt index a0d053d90..053ad4766 100644 --- a/app/src/main/java/com/nextcloud/talk/data/source/local/TalkDatabase.kt +++ b/app/src/main/java/com/nextcloud/talk/data/source/local/TalkDatabase.kt @@ -49,9 +49,9 @@ import java.util.Locale ChatMessageEntity::class, ChatBlockEntity::class ], - version = 11, + version = 12, autoMigrations = [ - AutoMigration(from = 9, to = 10) + AutoMigration(from = 9, to = 11) ], exportSchema = true ) @@ -113,7 +113,8 @@ abstract class TalkDatabase : RoomDatabase() { Migrations.MIGRATION_6_8, Migrations.MIGRATION_7_8, Migrations.MIGRATION_8_9, - Migrations.MIGRATION_10_11 + Migrations.MIGRATION_10_11, + Migrations.MIGRATION_11_12 ) .allowMainThreadQueries() .addCallback( diff --git a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt index d653b8098..e6a036564 100644 --- a/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt +++ b/app/src/main/java/com/nextcloud/talk/models/domain/ConversationModel.kt @@ -59,6 +59,7 @@ class ConversationModel( var recordingConsentRequired: Int = 0, var remoteServer: String? = null, var remoteToken: String? = null, + var hasArchived: Boolean = false, // attributes that don't come from API. This should be changed?! var password: String? = null @@ -120,7 +121,8 @@ class ConversationModel( callStartTime = conversation.callStartTime, recordingConsentRequired = conversation.recordingConsentRequired, remoteServer = conversation.remoteServer, - remoteToken = conversation.remoteToken + remoteToken = conversation.remoteToken, + hasArchived = conversation.hasArchived ) } } diff --git a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt index 2e48b7c81..6ef2bd50e 100644 --- a/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt +++ b/app/src/main/java/com/nextcloud/talk/models/json/conversations/Conversation.kt @@ -159,5 +159,8 @@ data class Conversation( var remoteServer: String? = "", @JsonField(name = ["remoteToken"]) - var remoteToken: String? = "" + var remoteToken: String? = "", + + @JsonField(name = ["isArchived"]) + var hasArchived: Boolean = false ) : Parcelable diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt index 80cf47990..2905da2e6 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepository.kt @@ -7,6 +7,7 @@ */ package com.nextcloud.talk.repositories.conversations +import com.nextcloud.talk.models.json.generic.GenericOverall import io.reactivex.Observable interface ConversationsRepository { @@ -29,4 +30,8 @@ interface ConversationsRepository { val successful: Boolean ) fun resendInvitations(token: String): Observable + + suspend fun archiveConversation(credentials: String, url: String): GenericOverall + + suspend fun unarchiveConversation(credentials: String, url: String): GenericOverall } diff --git a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt index 4b8972096..3f0549612 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/conversations/ConversationsRepositoryImpl.kt @@ -9,8 +9,10 @@ package com.nextcloud.talk.repositories.conversations import com.bluelinelabs.logansquare.LoganSquare import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.api.NcApiCoroutines import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.models.json.conversations.password.PasswordOverall +import com.nextcloud.talk.models.json.generic.GenericOverall import com.nextcloud.talk.repositories.conversations.ConversationsRepository.AllowGuestsResult import com.nextcloud.talk.repositories.conversations.ConversationsRepository.PasswordResult import com.nextcloud.talk.repositories.conversations.ConversationsRepository.ResendInvitationsResult @@ -20,6 +22,7 @@ import io.reactivex.Observable class ConversationsRepositoryImpl( private val api: NcApi, + private val coroutineApi: NcApiCoroutines, private val userProvider: CurrentUserProviderNew ) : ConversationsRepository { @@ -89,6 +92,14 @@ class ConversationsRepositoryImpl( } } + override suspend fun archiveConversation(credentials: String, url: String): GenericOverall { + return coroutineApi.archiveConversation(credentials, url) + } + + override suspend fun unarchiveConversation(credentials: String, url: String): GenericOverall { + return coroutineApi.unarchiveConversation(credentials, url) + } + private fun apiVersion(): Int { return ApiUtils.getConversationApiVersion(user, intArrayOf(ApiUtils.API_V4)) } diff --git a/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt b/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt index 486c505af..6eb3c1719 100644 --- a/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt +++ b/app/src/main/java/com/nextcloud/talk/ui/dialog/FilterConversationFragment.kt @@ -69,7 +69,8 @@ class FilterConversationFragment : DialogFragment() { binding.run { listOf( unreadFilterChip, - mentionedFilterChip + mentionedFilterChip, + archivedFilterChip ) }.forEach(viewThemeUtils.talk::themeChipFilter) @@ -89,6 +90,12 @@ class FilterConversationFragment : DialogFragment() { processSubmit() } + binding.archivedFilterChip.setOnCheckedChangeListener { _, isChecked -> + filterState[ARCHIVE] = isChecked + binding.archivedFilterChip.isChecked = isChecked + processSubmit() + } + binding.buttonClose.setOnClickListener { dismiss() } @@ -97,6 +104,7 @@ class FilterConversationFragment : DialogFragment() { private fun setUpChips() { binding.unreadFilterChip.isChecked = filterState[UNREAD]!! binding.mentionedFilterChip.isChecked = filterState[MENTION]!! + binding.archivedFilterChip.isChecked = filterState[ARCHIVE]!! } private fun processSubmit() { @@ -104,9 +112,11 @@ class FilterConversationFragment : DialogFragment() { val accountId = UserIdUtils.getIdForUser(userManager.currentUser.blockingGet()) val mentionValue = filterState[MENTION] == true val unreadValue = filterState[UNREAD] == true + val archivedValue = filterState[ARCHIVE] == true arbitraryStorageManager.storeStorageSetting(accountId, MENTION, mentionValue.toString(), "") arbitraryStorageManager.storeStorageSetting(accountId, UNREAD, unreadValue.toString(), "") + arbitraryStorageManager.storeStorageSetting(accountId, ARCHIVE, archivedValue.toString(), "") (requireActivity() as ConversationsListActivity).filterConversation() } @@ -126,5 +136,7 @@ class FilterConversationFragment : DialogFragment() { val TAG: String = FilterConversationFragment::class.java.simpleName const val MENTION: String = "mention" const val UNREAD: String = "unread" + const val ARCHIVE: String = "archive" + const val DEFAULT: String = "default" } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index fb4e6a770..557c876fc 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -588,4 +588,8 @@ object ApiUtils { fun getUrlForUnban(baseUrl: String, token: String, banId: Int): String { return "${getUrlForBans(baseUrl, token)}/$banId" } + + fun getUrlForArchive(version: Int, baseUrl: String?, token: String?): String { + return "${getUrlForRoom(version, baseUrl, token)}/archive" + } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt index 0a02bd914..996262296 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/CapabilitiesUtil.kt @@ -55,7 +55,8 @@ enum class SpreedFeatures(val value: String) { FEDERATION_V1("federation-v1"), DELETE_MESSAGES_UNLIMITED("delete-messages-unlimited"), BAN_V1("ban-v1"), - EDIT_MESSAGES_NOTE_TO_SELF("edit-messages-note-to-self") + EDIT_MESSAGES_NOTE_TO_SELF("edit-messages-note-to-self"), + ARCHIVE_CONVERSATIONS("archived-conversations") } @Suppress("TooManyFunctions") @@ -255,6 +256,10 @@ object CapabilitiesUtil { user.capabilities!!.spreedCapability!!.config!!["federation"]!!.containsKey("enabled") } + fun isArchiveConversationsAvailable(spreedCapabilities: SpreedCapability): Boolean { + return hasSpreedFeatureCapability(spreedCapabilities, SpreedFeatures.ARCHIVE_CONVERSATIONS) + } + // endregion //region ThemingCapabilities diff --git a/app/src/main/res/drawable/outline_archive_24.xml b/app/src/main/res/drawable/outline_archive_24.xml new file mode 100644 index 000000000..b94ba5dd9 --- /dev/null +++ b/app/src/main/res/drawable/outline_archive_24.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/activity_conversation_info.xml b/app/src/main/res/layout/activity_conversation_info.xml index 63738ce3d..ded8afea1 100644 --- a/app/src/main/res/layout/activity_conversation_info.xml +++ b/app/src/main/res/layout/activity_conversation_info.xml @@ -383,6 +383,44 @@ + + + + + + + + + + + + app:chipSpacingHorizontal="@dimen/standard_half_margin"> + + Show ban reason Error occurred when unbanning participant Connection lost + Archive Conversation + Unarchive Conversation + Archived + Once a conversation is archived, it will be hidden by default. Select the filter \'Archived\' to view archived conversations. Direct mentions will still be received. + Once a conversation is unarchived, it will be shown by default again.