From 721797c078e9749b11944c13804b84b71ffb02bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Kr=C3=BCger?= Date: Fri, 29 Apr 2022 13:41:54 +0200 Subject: [PATCH] Hide tabs without content in shared items view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Tim Krüger --- .../talk/activities/SharedItemsActivity.kt | 97 +++++++++++-------- .../java/com/nextcloud/talk/api/NcApi.java | 7 ++ .../json/chat/ChatShareOverviewOCS.java | 78 +++++++++++++++ .../json/chat/ChatShareOverviewOverall.java | 75 ++++++++++++++ .../talk/repositories/SharedItemType.kt | 18 ++++ .../repositories/SharedItemsRepository.kt | 18 +++- .../talk/repositories/SharedMediaItems.kt | 2 +- .../com/nextcloud/talk/utils/ApiUtils.java | 4 + .../talk/viewmodels/SharedItemsViewModel.kt | 51 +++++++++- 9 files changed, 299 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOCS.java create mode 100644 app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOverall.java create mode 100644 app/src/main/java/com/nextcloud/talk/repositories/SharedItemType.kt diff --git a/app/src/main/java/com/nextcloud/talk/activities/SharedItemsActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/SharedItemsActivity.kt index 5149ef2eb..00a60c0b7 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/SharedItemsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/SharedItemsActivity.kt @@ -15,6 +15,7 @@ import com.nextcloud.talk.adapters.SharedItemsAdapter import com.nextcloud.talk.adapters.SharedItemsListAdapter import com.nextcloud.talk.databinding.ActivitySharedItemsBinding import com.nextcloud.talk.models.database.UserEntity +import com.nextcloud.talk.repositories.SharedItemType import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN @@ -25,12 +26,12 @@ class SharedItemsActivity : AppCompatActivity() { private lateinit var binding: ActivitySharedItemsBinding private lateinit var viewModel: SharedItemsViewModel - private lateinit var currentTab: String + private lateinit var currentTab: SharedItemType override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - currentTab = TAB_MEDIA + currentTab = SharedItemType.MEDIA val roomToken = intent.getStringExtra(KEY_ROOM_TOKEN)!! val conversationName = intent.getStringExtra(KEY_CONVERSATION_NAME) @@ -54,17 +55,19 @@ class SharedItemsActivity : AppCompatActivity() { supportActionBar?.title = conversationName supportActionBar?.setDisplayHomeAsUpEnabled(true) - initTabs() - viewModel = ViewModelProvider( this, SharedItemsViewModel.Factory(userEntity, roomToken, currentTab) ).get(SharedItemsViewModel::class.java) + viewModel.sharedItemType.observe(this) { + initTabs(it) + } + viewModel.sharedItems.observe(this) { Log.d(TAG, "Items received: $it") - if (currentTab == TAB_MEDIA) { + if (currentTab == SharedItemType.MEDIA) { val adapter = SharedItemsAdapter() adapter.items = it.items adapter.authHeader = it.authHeader @@ -94,50 +97,65 @@ class SharedItemsActivity : AppCompatActivity() { }) } - fun updateItems(type: String) { + fun updateItems(type: SharedItemType) { currentTab = type viewModel.loadItems(type) } - private fun initTabs() { - val tabMedia: TabLayout.Tab = binding.sharedItemsTabs.newTab() - tabMedia.tag = TAB_MEDIA - tabMedia.setText(R.string.shared_items_media) - binding.sharedItemsTabs.addTab(tabMedia) + private fun initTabs(sharedItemTypes: Set) { - val tabFile: TabLayout.Tab = binding.sharedItemsTabs.newTab() - tabFile.tag = TAB_FILE - tabFile.setText(R.string.shared_items_file) - binding.sharedItemsTabs.addTab(tabFile) + if(sharedItemTypes.contains(SharedItemType.MEDIA)) { + val tabMedia: TabLayout.Tab = binding.sharedItemsTabs.newTab() + tabMedia.tag = SharedItemType.MEDIA + tabMedia.setText(R.string.shared_items_media) + binding.sharedItemsTabs.addTab(tabMedia) + } - val tabAudio: TabLayout.Tab = binding.sharedItemsTabs.newTab() - tabAudio.tag = TAB_AUDIO - tabAudio.setText(R.string.shared_items_audio) - binding.sharedItemsTabs.addTab(tabAudio) + if(sharedItemTypes.contains(SharedItemType.FILE)) { + val tabFile: TabLayout.Tab = binding.sharedItemsTabs.newTab() + tabFile.tag = SharedItemType.FILE + tabFile.setText(R.string.shared_items_file) + binding.sharedItemsTabs.addTab(tabFile) + } - val tabVoice: TabLayout.Tab = binding.sharedItemsTabs.newTab() - tabVoice.tag = TAB_VOICE - tabVoice.setText(R.string.shared_items_voice) - binding.sharedItemsTabs.addTab(tabVoice) + if(sharedItemTypes.contains(SharedItemType.AUDIO)) { + val tabAudio: TabLayout.Tab = binding.sharedItemsTabs.newTab() + tabAudio.tag = SharedItemType.AUDIO + tabAudio.setText(R.string.shared_items_audio) + binding.sharedItemsTabs.addTab(tabAudio) + } - // val tabLocation: TabLayout.Tab = binding.sharedItemsTabs.newTab() - // tabLocation.tag = TAB_LOCATION - // tabLocation.text = "location" - // binding.sharedItemsTabs.addTab(tabLocation) + if(sharedItemTypes.contains(SharedItemType.VOICE)) { + val tabVoice: TabLayout.Tab = binding.sharedItemsTabs.newTab() + tabVoice.tag = SharedItemType.VOICE + tabVoice.setText(R.string.shared_items_voice) + binding.sharedItemsTabs.addTab(tabVoice) + } - // val tabDeckCard: TabLayout.Tab = binding.sharedItemsTabs.newTab() - // tabDeckCard.tag = TAB_DECKCARD - // tabDeckCard.text = "deckcard" - // binding.sharedItemsTabs.addTab(tabDeckCard) + // if(sharedItemTypes.contains(SharedItemType.LOCATION)) { + // val tabLocation: TabLayout.Tab = binding.sharedItemsTabs.newTab() + // tabLocation.tag = SharedItemType.LOCATION + // tabLocation.text = "location" + // binding.sharedItemsTabs.addTab(tabLocation) + // } - // val tabOther: TabLayout.Tab = binding.sharedItemsTabs.newTab() - // tabOther.tag = TAB_OTHER - // tabOther.setText(R.string.shared_items_other) - // binding.sharedItemsTabs.addTab(tabOther) + // if(sharedItemTypes.contains(SharedItemType.DECKCARD)) { + // val tabDeckCard: TabLayout.Tab = binding.sharedItemsTabs.newTab() + // tabDeckCard.tag = SharedItemType.DECKCARD + // tabDeckCard.text = "deckcard" + // binding.sharedItemsTabs.addTab(tabDeckCard) + // } + + // if(sharedItemTypes.contains(SharedItemType.OTHER)) { + // val tabOther: TabLayout.Tab = binding.sharedItemsTabs.newTab() + // tabOther.tag = SharedItemType.OTHER + // tabOther.setText(R.string.shared_items_other) + // binding.sharedItemsTabs.addTab(tabOther) + // } binding.sharedItemsTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab) { - updateItems(tab.tag as String) + updateItems(tab.tag as SharedItemType) } override fun onTabUnselected(tab: TabLayout.Tab) = Unit @@ -157,13 +175,6 @@ class SharedItemsActivity : AppCompatActivity() { companion object { private val TAG = SharedItemsActivity::class.simpleName - const val TAB_AUDIO = "audio" - const val TAB_FILE = "file" - const val TAB_MEDIA = "media" - const val TAB_VOICE = "voice" - const val TAB_LOCATION = "location" - const val TAB_DECKCARD = "deckcard" - const val TAB_OTHER = "other" const val SPAN_COUNT: Int = 4 } } diff --git a/app/src/main/java/com/nextcloud/talk/api/NcApi.java b/app/src/main/java/com/nextcloud/talk/api/NcApi.java index 4c4133c60..857eabecc 100644 --- a/app/src/main/java/com/nextcloud/talk/api/NcApi.java +++ b/app/src/main/java/com/nextcloud/talk/api/NcApi.java @@ -28,6 +28,7 @@ import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall; import com.nextcloud.talk.models.json.chat.ChatOverall; import com.nextcloud.talk.models.json.chat.ChatOverallSingleMessage; import com.nextcloud.talk.models.json.chat.ChatShareOverall; +import com.nextcloud.talk.models.json.chat.ChatShareOverviewOverall; import com.nextcloud.talk.models.json.conversations.RoomOverall; import com.nextcloud.talk.models.json.conversations.RoomsOverall; import com.nextcloud.talk.models.json.generic.GenericOverall; @@ -345,6 +346,12 @@ public interface NcApi { @Nullable @Query("lastKnownMessageId") Integer lastKnownMessageId, @Nullable @Query("limit") Integer limit); + @GET + Observable> getSharedItemsOverview(@Header("Authorization") String authorization, + @Url String url, + @Nullable @Query("limit") Integer limit); + + @GET Observable getMentionAutocompleteSuggestions(@Header("Authorization") String authorization, @Url String url, @Query("search") String query, diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOCS.java b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOCS.java new file mode 100644 index 000000000..c6ae81b62 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOCS.java @@ -0,0 +1,78 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.nextcloud.talk.models.json.chat; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import org.parceler.Parcel; + +import java.util.HashMap; +import java.util.List; +import java.util.Objects; + +import androidx.annotation.NonNull; + +@Parcel +@JsonObject +public class ChatShareOverviewOCS { + @JsonField(name = "data") + public HashMap> data; + + public HashMap> getData() { + return this.data; + } + + public void setData(HashMap> data) { + this.data = data; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ChatShareOverviewOCS)) { + return false; + } + final ChatShareOverviewOCS other = (ChatShareOverviewOCS) o; + if (!other.canEqual(this)) { + return false; + } + final Object this$data = this.getData(); + final Object other$data = other.getData(); + + return Objects.equals(this$data, other$data); + } + + protected boolean canEqual(final Object other) { + return other instanceof ChatShareOverviewOCS; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $data = this.getData(); + return result * PRIME + ($data == null ? 43 : $data.hashCode()); + } + + public String toString() { + return "ChatShareOverviewOCS(data=" + this.getData() + ")"; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOverall.java b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOverall.java new file mode 100644 index 000000000..086a765d7 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/models/json/chat/ChatShareOverviewOverall.java @@ -0,0 +1,75 @@ +/* + * Nextcloud Talk application + * + * @author Mario Danic + * Copyright (C) 2017-2018 Mario Danic + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.nextcloud.talk.models.json.chat; + +import com.bluelinelabs.logansquare.annotation.JsonField; +import com.bluelinelabs.logansquare.annotation.JsonObject; + +import org.parceler.Parcel; + +import java.util.Objects; + +@Parcel +@JsonObject +public class ChatShareOverviewOverall { + @JsonField(name = "ocs") + public ChatShareOverviewOCS ocs; + + public ChatShareOverviewOCS getOcs() { + return this.ocs; + } + + public void setOcs(ChatShareOverviewOCS ocs) { + this.ocs = ocs; + } + + public boolean equals(final Object o) { + if (o == this) { + return true; + } + if (!(o instanceof ChatShareOverviewOverall)) { + return false; + } + final ChatShareOverviewOverall other = (ChatShareOverviewOverall) o; + if (!other.canEqual(this)) { + return false; + } + final Object this$ocs = this.getOcs(); + final Object other$ocs = other.getOcs(); + + return Objects.equals(this$ocs, other$ocs); + } + + protected boolean canEqual(final Object other) { + return other instanceof ChatShareOverviewOverall; + } + + public int hashCode() { + final int PRIME = 59; + int result = 1; + final Object $ocs = this.getOcs(); + return result * PRIME + ($ocs == null ? 43 : $ocs.hashCode()); + } + + public String toString() { + return "ChatShareOverviewOverall(ocs=" + this.getOcs() + ")"; + } +} diff --git a/app/src/main/java/com/nextcloud/talk/repositories/SharedItemType.kt b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemType.kt new file mode 100644 index 000000000..641ba72e6 --- /dev/null +++ b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemType.kt @@ -0,0 +1,18 @@ +package com.nextcloud.talk.repositories + +import java.util.Locale + +enum class SharedItemType { + + AUDIO, + FILE, + MEDIA, + VOICE, + LOCATION, + DECKCARD, + OTHER; + + companion object { + fun typeFor(name: String) = valueOf(name.uppercase(Locale.ROOT)) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt index b6dc0d4af..f34cd5497 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/SharedItemsRepository.kt @@ -7,9 +7,11 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.json.chat.ChatShareOverall +import com.nextcloud.talk.models.json.chat.ChatShareOverviewOverall import com.nextcloud.talk.utils.ApiUtils import io.reactivex.Observable import retrofit2.Response +import java.util.Locale import javax.inject.Inject @AutoInjector(NextcloudTalkApplication::class) @@ -24,22 +26,32 @@ class SharedItemsRepository { sharedApplication!!.componentApplication.inject(this) } - fun media(type: String): Observable>? { + fun media(type: SharedItemType): Observable>? { return media(type, null) } - fun media(type: String, lastKnownMessageId: Int?): Observable>? { + fun media(type: SharedItemType, lastKnownMessageId: Int?): Observable>? { val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken) return ncApi.getSharedItems( credentials, ApiUtils.getUrlForChatSharedItems(1, parameters!!.baseUrl, parameters!!.roomToken), - type, + type.toString().lowercase(Locale.ROOT), lastKnownMessageId, BATCH_SIZE ) } + fun availableTypes(): Observable>? { + val credentials = ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken) + + return ncApi.getSharedItemsOverview( + credentials, + ApiUtils.getUrlForChatSharedItemsOverview(1, parameters!!.baseUrl, parameters!!.roomToken), + 1 + ) + } + fun authHeader(): Map { return mapOf(Pair("Authorization", ApiUtils.getCredentials(parameters!!.userName, parameters!!.userToken))) } diff --git a/app/src/main/java/com/nextcloud/talk/repositories/SharedMediaItems.kt b/app/src/main/java/com/nextcloud/talk/repositories/SharedMediaItems.kt index 1e3b56bae..91f5fcf10 100644 --- a/app/src/main/java/com/nextcloud/talk/repositories/SharedMediaItems.kt +++ b/app/src/main/java/com/nextcloud/talk/repositories/SharedMediaItems.kt @@ -1,7 +1,7 @@ package com.nextcloud.talk.repositories class SharedMediaItems( - val type: String, + val type: SharedItemType, val items: MutableList, var lastSeenId: Int?, var moreItemsExisting: Boolean, diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java index 2b6e654c0..2199191f6 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.java @@ -265,6 +265,10 @@ public class ApiUtils { return getUrlForChat(version, baseUrl, token) + "/share"; } + public static String getUrlForChatSharedItemsOverview(int version, String baseUrl, String token) { + return getUrlForChatSharedItems(version, baseUrl, token) + "/overview"; + } + public static String getUrlForSignaling(int version, String baseUrl) { return getUrlForApi(version, baseUrl) + "/signaling"; } diff --git a/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt b/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt index 8e3b76602..6a935a438 100644 --- a/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt +++ b/app/src/main/java/com/nextcloud/talk/viewmodels/SharedItemsViewModel.kt @@ -7,7 +7,9 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import com.nextcloud.talk.models.database.UserEntity import com.nextcloud.talk.models.json.chat.ChatShareOverall +import com.nextcloud.talk.models.json.chat.ChatShareOverviewOverall import com.nextcloud.talk.repositories.SharedItem +import com.nextcloud.talk.repositories.SharedItemType import com.nextcloud.talk.repositories.SharedItemsRepository import com.nextcloud.talk.repositories.SharedMediaItems import io.reactivex.Observer @@ -16,15 +18,24 @@ import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import retrofit2.Response -class SharedItemsViewModel(private val repository: SharedItemsRepository, private val initialType: String) : +class SharedItemsViewModel(private val repository: SharedItemsRepository, private val initialType: SharedItemType) : ViewModel() { + private val _sharedItemType: MutableLiveData> by lazy { + MutableLiveData>().also { + availableTypes() + } + } + private val _sharedItems: MutableLiveData by lazy { MutableLiveData().also { loadItems(initialType) } } + val sharedItemType: LiveData> + get() = _sharedItemType + val sharedItems: LiveData get() = _sharedItems @@ -38,13 +49,13 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat } } - fun loadItems(type: String) { + fun loadItems(type: SharedItemType) { repository.media(type)?.subscribeOn(Schedulers.io()) ?.observeOn(AndroidSchedulers.mainThread()) ?.subscribe(observer(type, true)) } - private fun observer(type: String, initModel: Boolean): Observer> { + private fun observer(type: SharedItemType, initModel: Boolean): Observer> { return object : Observer> { var chatLastGiven: Int? = null @@ -119,7 +130,39 @@ class SharedItemsViewModel(private val repository: SharedItemsRepository, privat } } - class Factory(val userEntity: UserEntity, val roomToken: String, private val initialType: String) : + private fun availableTypes() { + repository.availableTypes()?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer> { + + val types = mutableSetOf() + + override fun onSubscribe(d: Disposable) = Unit + + override fun onNext(response: Response) { + val typeMap = response.body()!!.ocs!!.data + for (it in typeMap) { + if (it.value.size > 0) { + try { + types += SharedItemType.typeFor(it.key) + } catch (e: IllegalArgumentException) { + Log.w(TAG, "Server responds an unknown shared item type: ${it.key}") + } + } + } + } + + override fun onError(e: Throwable) { + Log.d(TAG, "An error occurred: $e") + } + + override fun onComplete() { + this@SharedItemsViewModel._sharedItemType.value = types + } + }) + } + + class Factory(val userEntity: UserEntity, val roomToken: String, private val initialType: SharedItemType) : ViewModelProvider .Factory {