mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-16 01:05:04 +01:00
Improvements & new search
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
93fb37a340
commit
689b8e93af
@ -1,249 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
|
||||||
*
|
|
||||||
* 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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.adapters.items
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.text.format.DateUtils
|
|
||||||
import android.util.Log
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import coil.api.load
|
|
||||||
import coil.transform.CircleCropTransformation
|
|
||||||
import com.nextcloud.talk.R
|
|
||||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
|
||||||
import com.nextcloud.talk.models.json.chat.ChatMessage
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
|
|
||||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
|
||||||
import com.nextcloud.talk.newarch.local.models.getCredentials
|
|
||||||
import com.nextcloud.talk.newarch.utils.Images
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
|
||||||
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
|
||||||
import eu.davidea.flexibleadapter.items.IFilterable
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
|
||||||
import eu.davidea.flexibleadapter.utils.FlexibleUtils
|
|
||||||
import eu.davidea.viewholders.FlexibleViewHolder
|
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
|
||||||
import kotlinx.android.synthetic.main.rv_item_conversation_with_last_message.*
|
|
||||||
import kotlinx.android.synthetic.main.rv_item_conversation_with_last_message.view.*
|
|
||||||
import java.util.*
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
class ConversationItem(
|
|
||||||
val model: Conversation,
|
|
||||||
val user: UserNgEntity,
|
|
||||||
private val context: Context
|
|
||||||
) : AbstractFlexibleItem<ConversationItem.ConversationItemViewHolder>(), IFilterable<String> {
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (other is ConversationItem) {
|
|
||||||
val inItem = other as ConversationItem?
|
|
||||||
val comparedConversation = inItem!!.model
|
|
||||||
|
|
||||||
return (model.conversationId == comparedConversation.conversationId
|
|
||||||
&& model.token == comparedConversation.token
|
|
||||||
&& model.name == comparedConversation.name
|
|
||||||
&& model.displayName == comparedConversation.displayName
|
|
||||||
&& model.type == comparedConversation.type
|
|
||||||
&& model.lastMessage == comparedConversation.lastMessage
|
|
||||||
&& model.favorite == comparedConversation.favorite
|
|
||||||
&& model.hasPassword == comparedConversation.hasPassword
|
|
||||||
&& model.unreadMessages == comparedConversation.unreadMessages
|
|
||||||
&& model.unreadMention == comparedConversation.unreadMention
|
|
||||||
&& model.objectType == comparedConversation.objectType
|
|
||||||
&& model.changing == comparedConversation.changing
|
|
||||||
&& inItem.user.id == user.id)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
return Objects.hash(
|
|
||||||
model.token,
|
|
||||||
user.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getLayoutRes(): Int {
|
|
||||||
return R.layout.rv_item_conversation_with_last_message
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createViewHolder(
|
|
||||||
view: View,
|
|
||||||
adapter: FlexibleAdapter<IFlexible<*>>
|
|
||||||
): ConversationItemViewHolder {
|
|
||||||
return ConversationItemViewHolder(view, adapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun bindViewHolder(
|
|
||||||
adapter: FlexibleAdapter<IFlexible<*>>,
|
|
||||||
holder: ConversationItemViewHolder,
|
|
||||||
position: Int,
|
|
||||||
payloads: List<Any>
|
|
||||||
) {
|
|
||||||
val appContext = NextcloudTalkApplication.sharedApplication!!.applicationContext
|
|
||||||
|
|
||||||
if (model.changing) {
|
|
||||||
holder.actionProgressBar!!.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
holder.actionProgressBar!!.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adapter.hasFilter()) {
|
|
||||||
FlexibleUtils.highlightText(
|
|
||||||
holder.dialogName!!, model.displayName,
|
|
||||||
adapter.getFilter(String::class.java).toString(),
|
|
||||||
NextcloudTalkApplication.sharedApplication!!
|
|
||||||
.resources.getColor(R.color.colorPrimary)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
holder.dialogName!!.text = model.displayName
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.unreadMessages > 0) {
|
|
||||||
holder.dialogUnreadBubble!!.visibility = View.VISIBLE
|
|
||||||
if (model.unreadMessages < 100) {
|
|
||||||
holder.dialogUnreadBubble!!.text = model.unreadMessages.toLong()
|
|
||||||
.toString()
|
|
||||||
} else {
|
|
||||||
holder.dialogUnreadBubble!!.text = context.getString(R.string.nc_99_plus)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.unreadMention) {
|
|
||||||
holder.dialogUnreadBubble!!.background =
|
|
||||||
context.getDrawable(R.drawable.bubble_circle_unread_mention)
|
|
||||||
} else {
|
|
||||||
holder.dialogUnreadBubble!!.background =
|
|
||||||
context.getDrawable(R.drawable.bubble_circle_unread)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
holder.dialogUnreadBubble!!.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.hasPassword) {
|
|
||||||
holder.passwordProtectedRoomImageView!!.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
holder.passwordProtectedRoomImageView!!.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.favorite) {
|
|
||||||
holder.favoriteConversationImageView!!.visibility = View.VISIBLE
|
|
||||||
} else {
|
|
||||||
holder.favoriteConversationImageView!!.visibility = View.GONE
|
|
||||||
}
|
|
||||||
|
|
||||||
if (model.lastMessage != null) {
|
|
||||||
holder.dialogDate!!.visibility = View.VISIBLE
|
|
||||||
holder.dialogDate!!.text = DateUtils.getRelativeTimeSpanString(
|
|
||||||
model.lastActivity * 1000L,
|
|
||||||
System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(
|
|
||||||
model.lastMessage!!.systemMessage
|
|
||||||
) || Conversation.ConversationType.SYSTEM_CONVERSATION == model.type
|
|
||||||
) {
|
|
||||||
holder.dialogLastMessage!!.text = model.lastMessage!!.text
|
|
||||||
} else {
|
|
||||||
var authorDisplayName = ""
|
|
||||||
model.lastMessage!!.activeUser = user
|
|
||||||
val text: String
|
|
||||||
if (model.lastMessage!!
|
|
||||||
.messageType == ChatMessage.MessageType.REGULAR_TEXT_MESSAGE && (!(ONE_TO_ONE_CONVERSATION).equals(
|
|
||||||
model.type) || model.lastMessage!!.actorId == user.userId)
|
|
||||||
) {
|
|
||||||
if (model.lastMessage!!.actorId == user.userId) {
|
|
||||||
text = String.format(
|
|
||||||
appContext.getString(R.string.nc_formatted_message_you),
|
|
||||||
model.lastMessage!!.lastMessageDisplayText
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
authorDisplayName = if (!TextUtils.isEmpty(model.lastMessage!!.actorDisplayName))
|
|
||||||
model.lastMessage!!.actorDisplayName
|
|
||||||
else if ("guests" == model.lastMessage!!.actorType)
|
|
||||||
appContext.getString(R.string.nc_guest)
|
|
||||||
else
|
|
||||||
""
|
|
||||||
text = String.format(
|
|
||||||
appContext.getString(R.string.nc_formatted_message),
|
|
||||||
authorDisplayName,
|
|
||||||
model.lastMessage!!.lastMessageDisplayText
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
text = model.lastMessage!!.lastMessageDisplayText
|
|
||||||
}
|
|
||||||
|
|
||||||
holder.dialogLastMessage.text = text
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
holder.dialogDate.visibility = View.GONE
|
|
||||||
holder.dialogLastMessage.setText(R.string.nc_no_messages_yet)
|
|
||||||
}
|
|
||||||
|
|
||||||
val conversationDrawable: Drawable? = Images().getImageForConversation(context, model)
|
|
||||||
|
|
||||||
conversationDrawable?.let {
|
|
||||||
holder.itemView.dialogAvatar.load(conversationDrawable)
|
|
||||||
}?: run {
|
|
||||||
holder.itemView.dialogAvatar.load(ApiUtils.getUrlForAvatarWithName(
|
|
||||||
user.baseUrl,
|
|
||||||
model.name, R.dimen.avatar_size))
|
|
||||||
{
|
|
||||||
addHeader("Authorization", user.getCredentials())
|
|
||||||
transformations(CircleCropTransformation())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewAttached(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?, holder: ConversationItemViewHolder?, position: Int) {
|
|
||||||
super.onViewAttached(adapter, holder, position)
|
|
||||||
Log.d("MAriO", model.displayName!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewDetached(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>?, holder: ConversationItemViewHolder?, position: Int) {
|
|
||||||
super.onViewDetached(adapter, holder, position)
|
|
||||||
Log.d("MAriO DETACH", model.displayName!!)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun filter(constraint: String): Boolean {
|
|
||||||
return model.displayName != null && Pattern.compile(
|
|
||||||
constraint, Pattern.CASE_INSENSITIVE or Pattern.LITERAL
|
|
||||||
)
|
|
||||||
.matcher(model.displayName!!.trim { it <= ' ' })
|
|
||||||
.find()
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConversationItemViewHolder(
|
|
||||||
view: View,
|
|
||||||
adapter: FlexibleAdapter<*>
|
|
||||||
) : FlexibleViewHolder(view, adapter), LayoutContainer {
|
|
||||||
|
|
||||||
override val containerView: View?
|
|
||||||
get() = itemView
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -20,11 +20,14 @@
|
|||||||
|
|
||||||
package com.nextcloud.talk.controllers.base
|
package com.nextcloud.talk.controllers.base
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.content.ComponentCallbacks
|
import android.content.ComponentCallbacks
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import android.util.TypedValue
|
||||||
|
import android.view.LayoutInflater
|
||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@ -33,7 +36,14 @@ import android.view.inputmethod.InputMethodManager
|
|||||||
import android.widget.EditText
|
import android.widget.EditText
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.ActionBar
|
import androidx.appcompat.app.ActionBar
|
||||||
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.core.view.marginBottom
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
|
import com.bluelinelabs.conductor.autodispose.ControllerScopeProvider
|
||||||
|
import com.google.android.material.appbar.AppBarLayout
|
||||||
|
import com.google.android.material.appbar.MaterialToolbar
|
||||||
|
import com.nextcloud.talk.R
|
||||||
|
import com.nextcloud.talk.activities.MainActivity
|
||||||
import com.nextcloud.talk.controllers.AccountVerificationController
|
import com.nextcloud.talk.controllers.AccountVerificationController
|
||||||
import com.nextcloud.talk.controllers.ServerSelectionController
|
import com.nextcloud.talk.controllers.ServerSelectionController
|
||||||
import com.nextcloud.talk.controllers.SwitchAccountController
|
import com.nextcloud.talk.controllers.SwitchAccountController
|
||||||
@ -41,6 +51,8 @@ import com.nextcloud.talk.controllers.WebViewLoginController
|
|||||||
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
|
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||||
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
import kotlinx.android.synthetic.main.search_layout.*
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -68,15 +80,39 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item.itemId) {
|
return when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
router.popCurrentController()
|
router.popCurrentController()
|
||||||
return true
|
true
|
||||||
}
|
}
|
||||||
else -> return super.onOptionsItemSelected(item)
|
else -> super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun showSearchOrToolbar() {
|
||||||
|
val value = getIsUsingSearchLayout()
|
||||||
|
activity?.let {
|
||||||
|
if (it is MainActivity) {
|
||||||
|
it.searchCardView.isVisible = value
|
||||||
|
it.inputEditText.hint = getSearchHint()
|
||||||
|
|
||||||
|
val layoutParams = it.toolbar.layoutParams as AppBarLayout.LayoutParams
|
||||||
|
|
||||||
|
if (value) {
|
||||||
|
it.appBar.setBackgroundResource(R.color.transparent)
|
||||||
|
//it.toolbar.setContentInsetsAbsolute(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 16f, resources?.displayMetrics).toInt(), 0)
|
||||||
|
//layoutParams.scrollFlags = AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL or AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS or AppBarLayout.LayoutParams.SCROLL_FLAG_SNAP
|
||||||
|
it.toolbar.layoutParams = layoutParams
|
||||||
|
} else {
|
||||||
|
it.appBar.setBackgroundResource(R.color.colorPrimary)
|
||||||
|
//it.toolbar.setContentInsetsAbsolute(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 24f, resources?.displayMetrics).toInt(), 0)
|
||||||
|
layoutParams.scrollFlags = 0
|
||||||
|
it.toolbar.layoutParams = layoutParams
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
private fun cleanTempCertPreference() {
|
private fun cleanTempCertPreference() {
|
||||||
val temporaryClassNames = ArrayList<String>()
|
val temporaryClassNames = ArrayList<String>()
|
||||||
temporaryClassNames.add(ServerSelectionController::class.java.name)
|
temporaryClassNames.add(ServerSelectionController::class.java.name)
|
||||||
@ -95,16 +131,22 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
|
|||||||
cleanTempCertPreference()
|
cleanTempCertPreference()
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
|
||||||
disableKeyboardPersonalisedLearning(view as ViewGroup)
|
disableKeyboardPersonalisedLearning(view as ViewGroup)
|
||||||
|
|
||||||
|
activity?.let {
|
||||||
|
if (it is MainActivity && getIsUsingSearchLayout()) {
|
||||||
|
disableKeyboardPersonalisedLearning(it.appBar)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAttach(view: View) {
|
override fun onAttach(view: View) {
|
||||||
super.onAttach(view)
|
super.onAttach(view)
|
||||||
|
|
||||||
setTitle()
|
setTitle()
|
||||||
if (actionBar != null) {
|
actionBar?.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize > 1)
|
||||||
actionBar!!.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize > 1)
|
showSearchOrToolbar()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDetach(view: View) {
|
override fun onDetach(view: View) {
|
||||||
@ -159,4 +201,7 @@ abstract class BaseController : ButterKnifeController(), ComponentCallbacks {
|
|||||||
open fun getTitle(): String? {
|
open fun getTitle(): String? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open fun getIsUsingSearchLayout(): Boolean = false
|
||||||
|
open fun getSearchHint(): String? = null
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,10 @@ class Conversation {
|
|||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
var changing: Boolean = false
|
var changing: Boolean = false
|
||||||
|
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
val isPublic: Boolean = ConversationType.PUBLIC_CONVERSATION == type
|
val isPublic: Boolean = ConversationType.PUBLIC_CONVERSATION == type
|
||||||
|
@JsonIgnore
|
||||||
val isGuest: Boolean =
|
val isGuest: Boolean =
|
||||||
Participant.ParticipantType.GUEST == participantType ||
|
Participant.ParticipantType.GUEST == participantType ||
|
||||||
Participant.ParticipantType.USER_FOLLOWING_LINK == participantType
|
Participant.ParticipantType.USER_FOLLOWING_LINK == participantType
|
||||||
@ -155,6 +158,48 @@ class Conversation {
|
|||||||
) || type != ConversationType.ONE_TO_ONE_CONVERSATION && participants!!.size > 1
|
) || type != ConversationType.ONE_TO_ONE_CONVERSATION && participants!!.size > 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as Conversation
|
||||||
|
|
||||||
|
if (databaseId != other.databaseId) return false
|
||||||
|
if (databaseUserId != other.databaseUserId) return false
|
||||||
|
if (conversationId != other.conversationId) return false
|
||||||
|
if (token != other.token) return false
|
||||||
|
if (name != other.name) return false
|
||||||
|
if (displayName != other.displayName) return false
|
||||||
|
if (type != other.type) return false
|
||||||
|
if (count != other.count) return false
|
||||||
|
if (numberOfGuests != other.numberOfGuests) return false
|
||||||
|
if (participants != other.participants) return false
|
||||||
|
if (participantType != other.participantType) return false
|
||||||
|
if (hasPassword != other.hasPassword) return false
|
||||||
|
if (password != other.password) return false
|
||||||
|
if (favorite != other.favorite) return false
|
||||||
|
if (lastActivity != other.lastActivity) return false
|
||||||
|
if (unreadMessages != other.unreadMessages) return false
|
||||||
|
if (unreadMention != other.unreadMention) return false
|
||||||
|
if (lastMessage != other.lastMessage) return false
|
||||||
|
if (objectType != other.objectType) return false
|
||||||
|
if (notificationLevel != other.notificationLevel) return false
|
||||||
|
if (conversationReadOnlyState != other.conversationReadOnlyState) return false
|
||||||
|
if (lobbyState != other.lobbyState) return false
|
||||||
|
if (lobbyTimer != other.lobbyTimer) return false
|
||||||
|
if (lastReadMessageId != other.lastReadMessageId) return false
|
||||||
|
if (canStartCall != other.canStartCall) return false
|
||||||
|
if (changing != other.changing) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = databaseUserId?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (token?.hashCode() ?: 0)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
enum class NotificationLevel {
|
enum class NotificationLevel {
|
||||||
DEFAULT,
|
DEFAULT,
|
||||||
ALWAYS,
|
ALWAYS,
|
||||||
|
@ -55,8 +55,12 @@ import com.nextcloud.talk.utils.bundle.BundleKeys
|
|||||||
import com.otaliastudios.elements.*
|
import com.otaliastudios.elements.*
|
||||||
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
import com.uber.autodispose.lifecycle.LifecycleScopeProvider
|
||||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
|
import kotlinx.android.synthetic.main.activity_main.view.*
|
||||||
import kotlinx.android.synthetic.main.controller_conversations_rv.view.*
|
import kotlinx.android.synthetic.main.controller_conversations_rv.view.*
|
||||||
import kotlinx.android.synthetic.main.message_state.view.*
|
import kotlinx.android.synthetic.main.message_state.view.*
|
||||||
|
import kotlinx.android.synthetic.main.search_layout.*
|
||||||
|
import kotlinx.android.synthetic.main.search_layout.view.*
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.parceler.Parcels
|
import org.parceler.Parcels
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -68,50 +72,6 @@ class ConversationsListView : BaseView() {
|
|||||||
private lateinit var viewModel: ConversationsListViewModel
|
private lateinit var viewModel: ConversationsListViewModel
|
||||||
val factory: ConversationListViewModelFactory by inject()
|
val factory: ConversationListViewModelFactory by inject()
|
||||||
|
|
||||||
private var searchItem: MenuItem? = null
|
|
||||||
private var settingsItem: MenuItem? = null
|
|
||||||
private var searchView: SearchView? = null
|
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(
|
|
||||||
menu: Menu,
|
|
||||||
inflater: MenuInflater
|
|
||||||
) {
|
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
|
||||||
inflater.inflate(R.menu.menu_conversation_plus_filter, menu)
|
|
||||||
searchItem = menu.findItem(R.id.action_search)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onPrepareOptionsMenu(menu: Menu) {
|
|
||||||
super.onPrepareOptionsMenu(menu)
|
|
||||||
settingsItem = menu.findItem(R.id.action_settings)
|
|
||||||
settingsItem?.actionView?.transitionName = "userAvatar.transitionTag"
|
|
||||||
viewModel.loadAvatar()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.action_settings -> {
|
|
||||||
val names = ArrayList<String>()
|
|
||||||
names.add("userAvatar.transitionTag")
|
|
||||||
router.pushController(
|
|
||||||
RouterTransaction.with(SettingsController())
|
|
||||||
.pushChangeHandler(
|
|
||||||
TransitionChangeHandlerCompat(
|
|
||||||
SharedElementTransition(names), VerticalChangeHandler()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.popChangeHandler(
|
|
||||||
TransitionChangeHandlerCompat(
|
|
||||||
SharedElementTransition(names), VerticalChangeHandler()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
else -> return super.onOptionsItemSelected(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*private fun initSearchView() {
|
/*private fun initSearchView() {
|
||||||
val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager
|
||||||
searchView = MenuItemCompat.getActionView(searchItem) as SearchView
|
searchView = MenuItemCompat.getActionView(searchItem) as SearchView
|
||||||
@ -144,7 +104,6 @@ class ConversationsListView : BaseView() {
|
|||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
container: ViewGroup
|
container: ViewGroup
|
||||||
): View {
|
): View {
|
||||||
setHasOptionsMenu(true)
|
|
||||||
actionBar?.show()
|
actionBar?.show()
|
||||||
|
|
||||||
viewModel = viewModelProvider(factory).get(ConversationsListViewModel::class.java)
|
viewModel = viewModelProvider(factory).get(ConversationsListViewModel::class.java)
|
||||||
@ -172,8 +131,26 @@ class ConversationsListView : BaseView() {
|
|||||||
swipeRefreshLayoutView.setColorSchemeResources(R.color.colorPrimary)
|
swipeRefreshLayoutView.setColorSchemeResources(R.color.colorPrimary)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
activity?.rightButton?.setOnClickListener {
|
||||||
|
val settingsTransitionName = "userAvatar.transitionTag"
|
||||||
|
router.pushController(
|
||||||
|
RouterTransaction.with(SettingsController())
|
||||||
|
.pushChangeHandler(
|
||||||
|
TransitionChangeHandlerCompat(
|
||||||
|
SharedElementTransition(arrayListOf(settingsTransitionName)), VerticalChangeHandler()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.popChangeHandler(
|
||||||
|
TransitionChangeHandlerCompat(
|
||||||
|
SharedElementTransition(arrayListOf(settingsTransitionName)), VerticalChangeHandler()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.avatar.observe(this@ConversationsListView) { avatar ->
|
viewModel.avatar.observe(this@ConversationsListView) { avatar ->
|
||||||
settingsItem?.icon = avatar
|
activity?.rightButton?.setImageDrawable(avatar)
|
||||||
}
|
}
|
||||||
|
|
||||||
return view
|
return view
|
||||||
@ -321,6 +298,14 @@ class ConversationsListView : BaseView() {
|
|||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getIsUsingSearchLayout(): Boolean {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSearchHint(): String? {
|
||||||
|
return resources?.getString(R.string.nc_search_conversations)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getTitle(): String? {
|
override fun getTitle(): String? {
|
||||||
return resources?.getString(R.string.nc_app_name)
|
return resources?.getString(R.string.nc_app_name)
|
||||||
}
|
}
|
||||||
|
28
app/src/main/res/drawable/ic_baseline_clear_24.xml
Normal file
28
app/src/main/res/drawable/ic_baseline_clear_24.xml
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<!--
|
||||||
|
~ /*
|
||||||
|
~ * Nextcloud Talk application
|
||||||
|
~ *
|
||||||
|
~ * @author Mario Danic
|
||||||
|
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~ *
|
||||||
|
~ * 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 <http://www.gnu.org/licenses/>.
|
||||||
|
~ */
|
||||||
|
-->
|
||||||
|
|
||||||
|
<vector android:autoMirrored="true" android:height="24dp"
|
||||||
|
android:tint="?attr/colorControlNormal"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="@android:color/white" android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
|
||||||
|
</vector>
|
@ -33,16 +33,27 @@
|
|||||||
|
|
||||||
<com.google.android.material.appbar.AppBarLayout
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_margin="0dp"
|
||||||
|
android:id="@+id/appBar"
|
||||||
|
app:elevation="0dp"
|
||||||
|
>
|
||||||
<com.google.android.material.appbar.MaterialToolbar
|
<com.google.android.material.appbar.MaterialToolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?android:attr/actionBarSize"
|
|
||||||
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
|
||||||
app:contentInsetStart="24dp"
|
android:layout_height="?android:attr/actionBarSize"
|
||||||
app:contentInsetStartWithNavigation="0dp"
|
android:background="@color/transparent"
|
||||||
app:popupTheme="@style/appActionBarPopupMenu" />
|
app:elevation="0dp"
|
||||||
|
app:contentInsetEnd="12dp"
|
||||||
|
app:contentInsetStart="12dp"
|
||||||
|
app:popupTheme="@style/appActionBarPopupMenu">
|
||||||
|
|
||||||
|
<include layout="@layout/search_layout"/>
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.MaterialToolbar>>
|
||||||
|
|
||||||
|
|
||||||
</com.google.android.material.appbar.AppBarLayout>
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
@ -38,7 +38,8 @@
|
|||||||
android:id="@+id/recyclerView"
|
android:id="@+id/recyclerView"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:listitem="@layout/rv_item_conversation_with_last_message" />
|
tools:listitem="@layout/rv_item_conversation_with_last_message"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
|
||||||
|
|
||||||
|
|
||||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||||
|
122
app/src/main/res/layout/search_layout.xml
Normal file
122
app/src/main/res/layout/search_layout.xml
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?><!--
|
||||||
|
~ /*
|
||||||
|
~ * Nextcloud Talk application
|
||||||
|
~ *
|
||||||
|
~ * @author Mario Danic
|
||||||
|
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
|
||||||
|
~ *
|
||||||
|
~ * 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 <http://www.gnu.org/licenses/>.
|
||||||
|
~ */
|
||||||
|
-->
|
||||||
|
|
||||||
|
<merge xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
>
|
||||||
|
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
android:id="@+id/searchCardView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:layout_marginVertical="8dp"
|
||||||
|
android:background="@color/transparent"
|
||||||
|
app:cardUseCompatPadding="false"
|
||||||
|
app:cardBackgroundColor="@color/transparent"
|
||||||
|
app:cardElevation="0dp"
|
||||||
|
android:elevation="0dp"
|
||||||
|
app:cardCornerRadius="4dp"
|
||||||
|
tools:cardCornerRadius="4dp"
|
||||||
|
tools:cardElevation="0dp"
|
||||||
|
android:clipToPadding="true"
|
||||||
|
android:clipChildren="true"
|
||||||
|
android:animateLayoutChanges="true"
|
||||||
|
android:layout_centerHorizontal="true">
|
||||||
|
|
||||||
|
<RelativeLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:clipToPadding="true"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@color/colorPrimary">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/leftContainer"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_centerVertical="true">
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/leftButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:tint="@color/fg_inverse"
|
||||||
|
android:src="@drawable/ic_arrow_back_black_24dp"
|
||||||
|
android:visibility="visible"
|
||||||
|
tools:src="@drawable/ic_arrow_back_black_24dp" />
|
||||||
|
|
||||||
|
<ProgressBar
|
||||||
|
android:id="@+id/progressBar"
|
||||||
|
style="?android:attr/progressBarStyle"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:indeterminateTint="@color/colorPrimary"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/inputEditText"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="start|center"
|
||||||
|
android:layout_toEndOf="@id/leftContainer"
|
||||||
|
android:layout_alignWithParentIfMissing="true"
|
||||||
|
android:inputType="textNoSuggestions"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:imeOptions="actionSearch|flagNoExtractUi"
|
||||||
|
android:lines="1"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:hint="Search"
|
||||||
|
android:layout_toStartOf="@id/rightButton"/>
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/rightButton"
|
||||||
|
android:layout_width="32dp"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:transitionName="userAvatar.transitionTag"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:background="?attr/selectableItemBackgroundBorderless"
|
||||||
|
android:src="@drawable/ic_settings_white_24dp"
|
||||||
|
tools:src="@tools:sample/avatars[0]"
|
||||||
|
android:visibility="visible" />
|
||||||
|
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
|
</merge>
|
@ -46,6 +46,7 @@
|
|||||||
|
|
||||||
<string name="nc_never">Never joined</string>
|
<string name="nc_never">Never joined</string>
|
||||||
<string name="nc_search">Search</string>
|
<string name="nc_search">Search</string>
|
||||||
|
<string name="nc_search_conversations">Search conversations</string>
|
||||||
|
|
||||||
<string name="nc_certificate_dialog_title">Check out the certificate</string>
|
<string name="nc_certificate_dialog_title">Check out the certificate</string>
|
||||||
<string name="nc_certificate_dialog_text">Do you trust the until now unknown SSL certificate, issued by %1$s for %2$s, valid from %3$s to %4$s?</string>
|
<string name="nc_certificate_dialog_text">Do you trust the until now unknown SSL certificate, issued by %1$s for %2$s, valid from %3$s to %4$s?</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user