WIP. Replace Controller with Activity for ConversationList

Signed-off-by: Marcel Hibbe <dev@mhibbe.de>
This commit is contained in:
Marcel Hibbe 2023-04-06 14:47:51 +02:00 committed by Andy Scherzinger
parent b975e8e4bd
commit aa1e93db05
No known key found for this signature in database
GPG Key ID: 6CADC7E3523C308B
12 changed files with 621 additions and 544 deletions

View File

@ -224,6 +224,10 @@
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:screenOrientation="portrait" /> android:screenOrientation="portrait" />
<activity
android:name=".conversationlist.ConversationsListActivity"
android:theme="@style/AppTheme" />
<receiver android:name=".receivers.PackageReplacedReceiver" <receiver android:name=".receivers.PackageReplacedReceiver"
android:exported="false"> android:exported="false">
<intent-filter> <intent-filter>

View File

@ -48,6 +48,10 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
open class BaseActivity : AppCompatActivity() { open class BaseActivity : AppCompatActivity() {
enum class AppBarLayoutType {
TOOLBAR, SEARCH_BAR, EMPTY
}
@Inject @Inject
lateinit var eventBus: EventBus lateinit var eventBus: EventBus
@ -60,6 +64,9 @@ open class BaseActivity : AppCompatActivity() {
@Inject @Inject
lateinit var context: Context lateinit var context: Context
open val appBarLayoutType: AppBarLayoutType
get() = AppBarLayoutType.TOOLBAR
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View File

@ -40,15 +40,14 @@ import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.controllers.ConversationsListController
import com.nextcloud.talk.controllers.LockedController import com.nextcloud.talk.controllers.LockedController
import com.nextcloud.talk.controllers.ServerSelectionController import com.nextcloud.talk.controllers.ServerSelectionController
import com.nextcloud.talk.controllers.WebViewLoginController 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.conversationlist.ConversationsListActivity
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ActivityMainBinding import com.nextcloud.talk.databinding.ActivityMainBinding
import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.conversations.RoomOverall
import com.nextcloud.talk.settings.SettingsActivity
import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.SecurityUtils import com.nextcloud.talk.utils.SecurityUtils
@ -165,11 +164,10 @@ class MainActivity : BaseActivity(), ActionBarProvider {
} }
private fun setDefaultRootController() { private fun setDefaultRootController() {
router!!.setRoot( val intent = Intent(this, ConversationsListActivity::class.java)
RouterTransaction.with(ConversationsListController(Bundle())) intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.pushChangeHandler(HorizontalChangeHandler()) intent.putExtras(Bundle())
.popChangeHandler(HorizontalChangeHandler()) startActivity(intent)
)
} }
fun resetConversationsList() { fun resetConversationsList() {
@ -192,11 +190,6 @@ class MainActivity : BaseActivity(), ActionBarProvider {
}) })
} }
fun openSettings() {
val intent = Intent(this, SettingsActivity::class.java)
startActivity(intent)
}
fun addAccount() { fun addAccount() {
router!!.pushController( router!!.pushController(
RouterTransaction.with(ServerSelectionController()) RouterTransaction.with(ServerSelectionController())

View File

@ -121,8 +121,8 @@ import com.nextcloud.talk.adapters.messages.VoiceMessageInterface
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.callbacks.MentionAutocompleteCallback import com.nextcloud.talk.callbacks.MentionAutocompleteCallback
import com.nextcloud.talk.controllers.ConversationsListController
import com.nextcloud.talk.conversation.info.ConversationInfoActivity import com.nextcloud.talk.conversation.info.ConversationInfoActivity
import com.nextcloud.talk.conversationlist.ConversationsListActivity
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ControllerChatBinding import com.nextcloud.talk.databinding.ControllerChatBinding
import com.nextcloud.talk.events.UserMentionClickEvent import com.nextcloud.talk.events.UserMentionClickEvent
@ -1763,7 +1763,7 @@ class ChatActivity :
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) { if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(ConversationsListController.TAG, "upload starting after permissions were granted") Log.d(ConversationsListActivity.TAG, "upload starting after permissions were granted")
if (filesToUpload.isNotEmpty()) { if (filesToUpload.isNotEmpty()) {
uploadFiles(filesToUpload) uploadFiles(filesToUpload)
} }
@ -3154,12 +3154,9 @@ class ChatActivity :
bundle.putString(BundleKeys.KEY_FORWARD_MSG_TEXT, message?.text) bundle.putString(BundleKeys.KEY_FORWARD_MSG_TEXT, message?.text)
bundle.putString(BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM, roomId) bundle.putString(BundleKeys.KEY_FORWARD_HIDE_SOURCE_ROOM, roomId)
// TODO val intent = Intent(this, ConversationsListActivity::class.java)
// router.pushController( intent.putExtras(bundle)
// RouterTransaction.with(ConversationsListController(bundle)) startActivity(intent)
// .pushChangeHandler(HorizontalChangeHandler())
// .popChangeHandler(HorizontalChangeHandler())
// )
} }
fun markAsUnread(message: IMessage?) { fun markAsUnread(message: IMessage?) {

View File

@ -22,6 +22,7 @@
package com.nextcloud.talk.controllers package com.nextcloud.talk.controllers
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
@ -42,6 +43,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.controllers.base.BaseController import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.controllers.util.viewBinding import com.nextcloud.talk.controllers.util.viewBinding
import com.nextcloud.talk.conversationlist.ConversationsListActivity
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ControllerAccountVerificationBinding import com.nextcloud.talk.databinding.ControllerAccountVerificationBinding
import com.nextcloud.talk.events.EventStatus import com.nextcloud.talk.events.EventStatus
@ -457,11 +459,8 @@ class AccountVerificationController(args: Bundle? = null) :
if (activity != null) { if (activity != null) {
activity!!.runOnUiThread { activity!!.runOnUiThread {
if (userManager.users.blockingGet().size == 1) { if (userManager.users.blockingGet().size == 1) {
router.setRoot( val intent = Intent(context, ConversationsListActivity::class.java)
RouterTransaction.with(ConversationsListController(Bundle())) startActivity(intent)
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else { } else {
if (isAccountImport) { if (isAccountImport) {
ApplicationWideMessageHolder.getInstance().messageType = ApplicationWideMessageHolder.getInstance().messageType =
@ -517,11 +516,8 @@ class AccountVerificationController(args: Bundle? = null) :
} }
} else { } else {
if (userManager.users.blockingGet().isNotEmpty()) { if (userManager.users.blockingGet().isNotEmpty()) {
router.setRoot( val intent = Intent(context, ConversationsListActivity::class.java)
RouterTransaction.with(ConversationsListController(Bundle())) startActivity(intent)
.pushChangeHandler(HorizontalChangeHandler())
.popChangeHandler(HorizontalChangeHandler())
)
} else { } else {
router.setRoot( router.setRoot(
RouterTransaction.with(ServerSelectionController()) RouterTransaction.with(ServerSelectionController())

View File

@ -22,10 +22,7 @@
*/ */
package com.nextcloud.talk.controllers.base package com.nextcloud.talk.controllers.base
import android.animation.AnimatorInflater
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.res.Resources
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@ -39,12 +36,10 @@ import android.widget.EditText
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.ActionBar import androidx.appcompat.app.ActionBar
import androidx.core.content.res.ResourcesCompat
import autodagger.AutoInjector import autodagger.AutoInjector
import com.bluelinelabs.conductor.Controller import com.bluelinelabs.conductor.Controller
import com.bluelinelabs.conductor.ControllerChangeHandler import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType import com.bluelinelabs.conductor.ControllerChangeType
import com.google.android.material.appbar.AppBarLayout
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MainActivity import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
@ -54,9 +49,7 @@ import com.nextcloud.talk.controllers.ServerSelectionController
import com.nextcloud.talk.controllers.SwitchAccountController import com.nextcloud.talk.controllers.SwitchAccountController
import com.nextcloud.talk.controllers.WebViewLoginController 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.databinding.ActivityMainBinding
import com.nextcloud.talk.ui.theme.ViewThemeUtils import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.utils.preferences.AppPreferences
import javax.inject.Inject import javax.inject.Inject
import kotlin.jvm.internal.Intrinsics import kotlin.jvm.internal.Intrinsics
@ -120,12 +113,12 @@ abstract class BaseController(@LayoutRes var layoutRes: Int, args: Bundle? = nul
protected open fun onViewBound(view: View) { protected open fun onViewBound(view: View) {
var activity: MainActivity? = null var activity: MainActivity? = null
if (getActivity() != null && getActivity() is MainActivity) { // if (getActivity() != null && getActivity() is MainActivity) {
activity = getActivity() as MainActivity? // activity = getActivity() as MainActivity?
viewThemeUtils.material.themeCardView(activity!!.binding.searchToolbar) // viewThemeUtils.material.themeCardView(activity!!.binding.searchToolbar)
viewThemeUtils.material.themeToolbar(activity.binding.toolbar) // viewThemeUtils.material.themeToolbar(activity.binding.toolbar)
viewThemeUtils.material.themeSearchBarText(activity.binding.searchText) // viewThemeUtils.material.themeSearchBarText(activity.binding.searchText)
} // }
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))
@ -136,7 +129,7 @@ abstract class BaseController(@LayoutRes var layoutRes: Int, args: Bundle? = nul
} }
override fun onAttach(view: View) { override fun onAttach(view: View) {
showSearchOrToolbar() // showSearchOrToolbar()
setTitle() setTitle()
if (actionBar != null) { if (actionBar != null) {
actionBar!!.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize >= 1) actionBar!!.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize >= 1)
@ -144,93 +137,93 @@ abstract class BaseController(@LayoutRes var layoutRes: Int, args: Bundle? = nul
super.onAttach(view) super.onAttach(view)
} }
open fun showSearchOrToolbar() { // open fun showSearchOrToolbar() {
if (isValidActivity(activity)) { // if (isValidActivity(activity)) {
val showSearchBar = appBarLayoutType == AppBarLayoutType.SEARCH_BAR // val showSearchBar = appBarLayoutType == AppBarLayoutType.SEARCH_BAR
val activity = activity as MainActivity // val activity = activity as MainActivity
//
if (appBarLayoutType == AppBarLayoutType.EMPTY) { // if (appBarLayoutType == AppBarLayoutType.EMPTY) {
hideBars(activity.binding) // hideBars(activity.binding)
} else { // } else {
if (showSearchBar) { // if (showSearchBar) {
showSearchBar(activity.binding) // showSearchBar(activity.binding)
} else { // } else {
showToolbar(activity.binding) // showToolbar(activity.binding)
} // }
colorizeStatusBar(showSearchBar, activity, resources) // colorizeStatusBar(showSearchBar, activity, resources)
} // }
//
colorizeNavigationBar(activity, resources) // colorizeNavigationBar(activity, resources)
} // }
} // }
//
private fun isValidActivity(activity: Activity?): Boolean { // private fun isValidActivity(activity: Activity?): Boolean {
return activity != null && activity is MainActivity // return activity != null && activity is MainActivity
} // }
//
private fun showSearchBar(binding: ActivityMainBinding) { // private fun showSearchBar(binding: ActivityMainBinding) {
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams // val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
binding.searchToolbar.visibility = View.VISIBLE // binding.searchToolbar.visibility = View.VISIBLE
binding.searchText.hint = searchHint // binding.searchText.hint = searchHint
binding.toolbar.visibility = View.GONE // binding.toolbar.visibility = View.GONE
// layoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout // // layoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout
// .LayoutParams.SCROLL_FLAG_SNAP | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS); // // .LayoutParams.SCROLL_FLAG_SNAP | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
layoutParams.scrollFlags = 0 // layoutParams.scrollFlags = 0
binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator( // binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
binding.appBar.context, // binding.appBar.context,
R.animator.appbar_elevation_off // R.animator.appbar_elevation_off
) // )
binding.searchToolbar.layoutParams = layoutParams // binding.searchToolbar.layoutParams = layoutParams
} // }
//
private fun showToolbar(binding: ActivityMainBinding) { // private fun showToolbar(binding: ActivityMainBinding) {
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams // val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
binding.searchToolbar.visibility = View.GONE // binding.searchToolbar.visibility = View.GONE
binding.toolbar.visibility = View.VISIBLE // binding.toolbar.visibility = View.VISIBLE
viewThemeUtils.material.colorToolbarOverflowIcon(binding.toolbar) // viewThemeUtils.material.colorToolbarOverflowIcon(binding.toolbar)
layoutParams.scrollFlags = 0 // layoutParams.scrollFlags = 0
binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator( // binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
binding.appBar.context, // binding.appBar.context,
R.animator.appbar_elevation_on // R.animator.appbar_elevation_on
) // )
binding.searchToolbar.layoutParams = layoutParams // binding.searchToolbar.layoutParams = layoutParams
} // }
//
private fun hideBars(binding: ActivityMainBinding) { // private fun hideBars(binding: ActivityMainBinding) {
binding.toolbar.visibility = View.GONE // binding.toolbar.visibility = View.GONE
binding.searchToolbar.visibility = View.GONE // binding.searchToolbar.visibility = View.GONE
} // }
//
fun hideSearchBar() { // fun hideSearchBar() {
val activity = activity as MainActivity? // val activity = activity as MainActivity?
val layoutParams = activity!!.binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams // val layoutParams = activity!!.binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
activity.binding.searchToolbar.visibility = View.GONE // activity.binding.searchToolbar.visibility = View.GONE
activity.binding.toolbar.visibility = View.VISIBLE // activity.binding.toolbar.visibility = View.VISIBLE
layoutParams.scrollFlags = 0 // layoutParams.scrollFlags = 0
activity.binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator( // activity.binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
activity.binding.appBar.context, // activity.binding.appBar.context,
R.animator.appbar_elevation_on // R.animator.appbar_elevation_on
) // )
} // }
//
private fun colorizeStatusBar(showSearchBar: Boolean, activity: Activity?, resources: Resources?) { // private fun colorizeStatusBar(showSearchBar: Boolean, activity: Activity?, resources: Resources?) {
if (activity != null && resources != null) { // if (activity != null && resources != null) {
if (showSearchBar) { // if (showSearchBar) {
view?.let { viewThemeUtils.platform.resetStatusBar(activity) } // view?.let { viewThemeUtils.platform.resetStatusBar(activity) }
} else { // } else {
view?.let { viewThemeUtils.platform.themeStatusBar(activity, it) } // view?.let { viewThemeUtils.platform.themeStatusBar(activity, it) }
} // }
} // }
} // }
//
private fun colorizeNavigationBar(activity: Activity?, resources: Resources?) { // private fun colorizeNavigationBar(activity: Activity?, resources: Resources?) {
if (activity != null && resources != null) { // if (activity != null && resources != null) {
DisplayUtils.applyColorToNavigationBar( // DisplayUtils.applyColorToNavigationBar(
activity.window, // activity.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null) // ResourcesCompat.getColor(resources, R.color.bg_default, null)
) // )
} // }
} // }
override fun onDetach(view: View) { override fun onDetach(view: View) {
super.onDetach(view) super.onDetach(view)

View File

@ -23,14 +23,17 @@
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.nextcloud.talk.controllers package com.nextcloud.talk.conversationlist
import android.animation.AnimatorInflater import android.animation.AnimatorInflater
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Activity
import android.app.SearchManager import android.app.SearchManager
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
@ -40,7 +43,6 @@ import android.text.InputType
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.MotionEvent import android.view.MotionEvent
import android.view.View import android.view.View
@ -49,6 +51,7 @@ import android.view.inputmethod.InputMethodManager
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.SearchView import androidx.appcompat.widget.SearchView
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.MenuItemCompat import androidx.core.view.MenuItemCompat
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
@ -60,13 +63,12 @@ import coil.imageLoader
import coil.request.ImageRequest import coil.request.ImageRequest
import coil.target.Target import coil.target.Target
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import com.bluelinelabs.conductor.RouterTransaction import com.google.android.material.appbar.AppBarLayout
import com.bluelinelabs.conductor.changehandler.VerticalChangeHandler
import com.google.android.material.button.MaterialButton import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.activities.CallActivity
import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.adapters.items.ConversationItem import com.nextcloud.talk.adapters.items.ConversationItem
import com.nextcloud.talk.adapters.items.GenericTextHeaderItem import com.nextcloud.talk.adapters.items.GenericTextHeaderItem
import com.nextcloud.talk.adapters.items.LoadMoreResultsItem import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
@ -74,11 +76,8 @@ import com.nextcloud.talk.adapters.items.MessageResultItem
import com.nextcloud.talk.adapters.items.MessagesTextHeaderItem import com.nextcloud.talk.adapters.items.MessagesTextHeaderItem
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.chat.ChatActivity
import com.nextcloud.talk.contacts.ContactsActivity import com.nextcloud.talk.contacts.ContactsActivity
import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.controllers.util.viewBinding
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ControllerConversationsRvBinding import com.nextcloud.talk.databinding.ControllerConversationsRvBinding
import com.nextcloud.talk.events.ConversationsListFetchDataEvent import com.nextcloud.talk.events.ConversationsListFetchDataEvent
@ -100,6 +99,7 @@ import com.nextcloud.talk.ui.dialog.ConversationsListBottomDialog
import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.users.UserManager
import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.ClosedInterfaceImpl import com.nextcloud.talk.utils.ClosedInterfaceImpl
import com.nextcloud.talk.utils.DisplayUtils
import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.FileUtils
import com.nextcloud.talk.utils.Mimetype import com.nextcloud.talk.utils.Mimetype
import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.ParticipantPermissions
@ -130,7 +130,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers import io.reactivex.schedulers.Schedulers
import org.apache.commons.lang3.builder.CompareToBuilder import org.apache.commons.lang3.builder.CompareToBuilder
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode import org.greenrobot.eventbus.ThreadMode
import org.parceler.Parcels import org.parceler.Parcels
@ -140,19 +139,17 @@ import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class ConversationsListController(bundle: Bundle) : class ConversationsListActivity :
BaseController(R.layout.controller_conversations_rv, bundle), BaseActivity(),
FlexibleAdapter.OnItemClickListener, FlexibleAdapter.OnItemClickListener,
FlexibleAdapter.OnItemLongClickListener, FlexibleAdapter.OnItemLongClickListener,
ConversationMenuInterface { ConversationMenuInterface {
private val bundle: Bundle
private lateinit var binding: ControllerConversationsRvBinding
@Inject @Inject
lateinit var userManager: UserManager lateinit var userManager: UserManager
@Inject
lateinit var eventBus: EventBus
@Inject @Inject
lateinit var ncApi: NcApi lateinit var ncApi: NcApi
@ -162,11 +159,6 @@ class ConversationsListController(bundle: Bundle) :
@Inject @Inject
lateinit var platformPermissionUtil: PlatformPermissionUtil lateinit var platformPermissionUtil: PlatformPermissionUtil
private val binding: ControllerConversationsRvBinding? by viewBinding(ControllerConversationsRvBinding::bind)
override val title: String
get() = resources!!.getString(R.string.nc_app_product_name)
override val appBarLayoutType: AppBarLayoutType override val appBarLayoutType: AppBarLayoutType
get() = AppBarLayoutType.SEARCH_BAR get() = AppBarLayoutType.SEARCH_BAR
@ -190,7 +182,7 @@ class ConversationsListController(bundle: Bundle) :
private var selectedConversation: Conversation? = null private var selectedConversation: Conversation? = null
private var textToPaste: String? = "" private var textToPaste: String? = ""
private var selectedMessageId: String? = null private var selectedMessageId: String? = null
private var forwardMessage: Boolean private var forwardMessage: Boolean = false
private var nextUnreadConversationScrollPosition = 0 private var nextUnreadConversationScrollPosition = 0
private var layoutManager: SmoothScrollLinearLayoutManager? = null private var layoutManager: SmoothScrollLinearLayoutManager? = null
private val callHeaderItems = HashMap<String, GenericTextHeaderItem>() private val callHeaderItems = HashMap<String, GenericTextHeaderItem>()
@ -198,46 +190,110 @@ class ConversationsListController(bundle: Bundle) :
private var searchHelper: MessageSearchHelper? = null private var searchHelper: MessageSearchHelper? = null
private var searchViewDisposable: Disposable? = null private var searchViewDisposable: Disposable? = null
override fun onViewBound(view: View) { override fun onCreate(savedInstanceState: Bundle?) {
super.onViewBound(view) super.onCreate(savedInstanceState)
sharedApplication!!.componentApplication.inject(this) NextcloudTalkApplication.sharedApplication!!.componentApplication.inject(this)
actionBar?.show()
binding = ControllerConversationsRvBinding.inflate(layoutInflater)
setupActionBar()
setupSystemColors()
setContentView(binding.root)
forwardMessage = intent.getBooleanExtra(KEY_FORWARD_MSG_FLAG, false)
}
override fun onResume() {
super.onResume()
// actionBar?.show()
if (adapter == null) { if (adapter == null) {
adapter = FlexibleAdapter(conversationItems, activity, true) adapter = FlexibleAdapter(conversationItems, this, true)
} else { } else {
binding?.loadingContent?.visibility = View.GONE binding?.loadingContent?.visibility = View.GONE
} }
adapter!!.addListener(this) adapter!!.addListener(this)
prepareViews() prepareViews()
showShareToScreen = hasActivityActionSendIntent()
ClosedInterfaceImpl().setUpPushTokenRegistration()
if (!eventBus.isRegistered(this)) {
eventBus.register(this)
}
currentUser = userManager.currentUser.blockingGet()
if (currentUser != null) {
if (isServerEOL(currentUser!!)) {
showServerEOLDialog()
return
}
if (isUnifiedSearchAvailable(currentUser!!)) {
searchHelper = MessageSearchHelper(unifiedSearchRepository)
}
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
loadUserAvatar(binding.switchAccountButton)
viewThemeUtils.material.colorMaterialTextButton(binding.switchAccountButton)
fetchRooms()
} else {
Log.e(TAG, "userManager.currentUser.blockingGet() returned null")
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
}
showSearchOrToolbar()
}
private fun setupActionBar() {
setSupportActionBar(binding.conversationListToolbar)
binding.conversationListToolbar.setNavigationOnClickListener {
onBackPressed()
}
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setIcon(ColorDrawable(resources!!.getColor(R.color.transparent)))
supportActionBar?.title = resources!!.getString(R.string.nc_app_product_name)
}
private fun setupSystemColors() {
DisplayUtils.applyColorToStatusBar(
this,
ResourcesCompat.getColor(
resources,
R.color.appbar,
null
)
)
DisplayUtils.applyColorToNavigationBar(
this.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null)
)
} }
private fun loadUserAvatar( private fun loadUserAvatar(
target: Target target: Target
) { ) {
if (activity != null) { if (currentUser != null) {
if (currentUser != null) { val url = ApiUtils.getUrlForAvatar(
val url = ApiUtils.getUrlForAvatar( currentUser!!.baseUrl,
currentUser!!.baseUrl, currentUser!!.userId,
currentUser!!.userId, true
true )
)
val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token) val credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
context.imageLoader.enqueue( context.imageLoader.enqueue(
ImageRequest.Builder(context) ImageRequest.Builder(context)
.data(url) .data(url)
.addHeader("Authorization", credentials) .addHeader("Authorization", credentials)
.placeholder(R.drawable.ic_user) .placeholder(R.drawable.ic_user)
.transformations(CircleCropTransformation()) .transformations(CircleCropTransformation())
.crossfade(true) .crossfade(true)
.target(target) .target(target)
.build() .build()
) )
} else { } else {
Log.e(TAG, "currentUser was null in loadUserAvatar") Log.e(TAG, "currentUser was null in loadUserAvatar")
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show() Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
}
} }
} }
@ -268,92 +324,44 @@ class ConversationsListController(bundle: Bundle) :
loadUserAvatar(target) loadUserAvatar(target)
} }
override fun onAttach(view: View) {
Log.d(
TAG,
"onAttach: Controller: " + System.identityHashCode(this) +
" Activity: " + System.identityHashCode(activity)
)
super.onAttach(view)
showShareToScreen = hasActivityActionSendIntent()
ClosedInterfaceImpl().setUpPushTokenRegistration()
if (!eventBus.isRegistered(this)) {
eventBus.register(this)
}
currentUser = userManager.currentUser.blockingGet()
if (currentUser != null) {
if (isServerEOL(currentUser!!)) {
showServerEOLDialog()
return
}
if (isUnifiedSearchAvailable(currentUser!!)) {
searchHelper = MessageSearchHelper(unifiedSearchRepository)
}
credentials = ApiUtils.getCredentials(currentUser!!.username, currentUser!!.token)
if (activity != null && activity is MainActivity) {
loadUserAvatar((activity as MainActivity?)!!.binding.switchAccountButton)
viewThemeUtils.material
.colorMaterialTextButton((activity as MainActivity?)!!.binding.switchAccountButton)
}
fetchRooms()
} else {
Log.e(TAG, "userManager.currentUser.blockingGet() returned null")
Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
}
}
override fun onDetach(view: View) {
Log.d(
TAG,
"onDetach: Controller: " + System.identityHashCode(this) +
" Activity: " + System.identityHashCode(activity)
)
super.onDetach(view)
eventBus.unregister(this)
}
private fun initSearchView() { private fun initSearchView() {
if (activity != null) { val searchManager = getSystemService(Context.SEARCH_SERVICE) as SearchManager?
val searchManager = activity!!.getSystemService(Context.SEARCH_SERVICE) as SearchManager? if (searchItem != null) {
if (searchItem != null) { searchView = MenuItemCompat.getActionView(searchItem) as SearchView
searchView = MenuItemCompat.getActionView(searchItem) as SearchView viewThemeUtils.talk.themeSearchView(searchView!!)
viewThemeUtils.talk.themeSearchView(searchView!!) searchView!!.maxWidth = Int.MAX_VALUE
searchView!!.maxWidth = Int.MAX_VALUE searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER
searchView!!.inputType = InputType.TYPE_TEXT_VARIATION_FILTER var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN
var imeOptions = EditorInfo.IME_ACTION_DONE or EditorInfo.IME_FLAG_NO_FULLSCREEN if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences.isKeyboardIncognito) { imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
imeOptions = imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
}
searchView!!.imeOptions = imeOptions
searchView!!.queryHint = searchHint
if (searchManager != null) {
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(activity!!.componentName))
}
searchViewDisposable = observeSearchView(searchView!!)
.debounce { query: String? ->
if (TextUtils.isEmpty(query)) {
return@debounce Observable.empty<Long>()
} else {
return@debounce Observable.timer(
SEARCH_DEBOUNCE_INTERVAL_MS.toLong(),
TimeUnit.MILLISECONDS
)
}
}
.distinctUntilChanged()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newText: String? -> onQueryTextChange(newText) }
} }
searchView!!.imeOptions = imeOptions
searchView!!.queryHint = getString(R.string.appbar_search_in, getString(R.string.nc_app_product_name))
if (searchManager != null) {
searchView!!.setSearchableInfo(searchManager.getSearchableInfo(componentName))
}
searchViewDisposable = observeSearchView(searchView!!)
.debounce { query: String? ->
if (TextUtils.isEmpty(query)) {
return@debounce Observable.empty<Long>()
} else {
return@debounce Observable.timer(
SEARCH_DEBOUNCE_INTERVAL_MS.toLong(),
TimeUnit.MILLISECONDS
)
}
}
.distinctUntilChanged()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { newText: String? -> onQueryTextChange(newText) }
} }
} }
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu, inflater) super.onCreateOptionsMenu(menu)
inflater.inflate(R.menu.menu_conversation_plus_filter, menu) menuInflater.inflate(R.menu.menu_conversation_plus_filter, menu)
searchItem = menu.findItem(R.id.action_search) searchItem = menu.findItem(R.id.action_search)
chooseAccountItem = menu.findItem(R.id.action_choose_account) chooseAccountItem = menu.findItem(R.id.action_choose_account)
loadUserAvatar(chooseAccountItem!!) loadUserAvatar(chooseAccountItem!!)
@ -362,17 +370,19 @@ class ConversationsListController(bundle: Bundle) :
if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) { if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) {
val newFragment: DialogFragment = ChooseAccountShareToDialogFragment.newInstance() val newFragment: DialogFragment = ChooseAccountShareToDialogFragment.newInstance()
newFragment.show( newFragment.show(
(activity as MainActivity?)!!.supportFragmentManager, supportFragmentManager,
ChooseAccountShareToDialogFragment.TAG ChooseAccountShareToDialogFragment.TAG
) )
} }
true true
} }
initSearchView() initSearchView()
return true
} }
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu): Boolean {
super.onPrepareOptionsMenu(menu) super.onPrepareOptionsMenu(menu)
searchView = MenuItemCompat.getActionView(searchItem) as SearchView searchView = MenuItemCompat.getActionView(searchItem) as SearchView
val moreAccountsAvailable = userManager.users.blockingGet().size > 1 val moreAccountsAvailable = userManager.users.blockingGet().size > 1
@ -385,24 +395,19 @@ class ConversationsListController(bundle: Bundle) :
hideSearchBar() hideSearchBar()
actionBar?.setTitle(R.string.nc_forward_to_three_dots) actionBar?.setTitle(R.string.nc_forward_to_three_dots)
} else { } else {
val activity = activity as MainActivity?
searchItem!!.isVisible = conversationItems.size > 0 searchItem!!.isVisible = conversationItems.size > 0
if (activity != null) { if (adapter!!.hasFilter()) {
if (adapter!!.hasFilter()) { showSearchView(searchView, searchItem)
showSearchView(activity, searchView, searchItem) searchView!!.setQuery(adapter!!.getFilter(String::class.java), false)
searchView!!.setQuery(adapter!!.getFilter(String::class.java), false) }
} binding.searchText.setOnClickListener {
activity.binding.searchText.setOnClickListener { showSearchView(searchView, searchItem)
showSearchView(activity, searchView, searchItem) viewThemeUtils.platform.themeStatusBar(this, searchView!!)
viewThemeUtils.platform.themeStatusBar(activity, searchView!!)
}
} }
searchView!!.setOnCloseListener { searchView!!.setOnCloseListener {
if (TextUtils.isEmpty(searchView!!.query.toString())) { if (TextUtils.isEmpty(searchView!!.query.toString())) {
searchView!!.onActionViewCollapsed() searchView!!.onActionViewCollapsed()
if (activity != null) { viewThemeUtils.platform.resetStatusBar(this)
viewThemeUtils.platform.resetStatusBar(activity)
}
} else { } else {
searchView!!.post { searchView!!.setQuery(TAG, true) } searchView!!.post { searchView!!.setQuery(TAG, true) }
} }
@ -428,48 +433,118 @@ class ConversationsListController(bundle: Bundle) :
} }
binding?.swipeRefreshLayoutView?.isEnabled = true binding?.swipeRefreshLayoutView?.isEnabled = true
searchView!!.onActionViewCollapsed() searchView!!.onActionViewCollapsed()
val mainActivity = getActivity() as MainActivity?
if (mainActivity != null) { binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
mainActivity.binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator( binding.conversationListAppbar.context,
mainActivity.binding.appBar.context, R.animator.appbar_elevation_off
R.animator.appbar_elevation_off )
) binding.conversationListToolbar.visibility = View.GONE
mainActivity.binding.toolbar.visibility = View.GONE binding.searchToolbar.visibility = View.VISIBLE
mainActivity.binding.searchToolbar.visibility = View.VISIBLE if (resources != null) {
if (resources != null) { viewThemeUtils.platform.resetStatusBar(this@ConversationsListActivity)
viewThemeUtils.platform
.resetStatusBar(mainActivity)
}
} }
val layoutManager = binding?.recyclerView?.layoutManager as SmoothScrollLinearLayoutManager? val layoutManager = binding?.recyclerView?.layoutManager as SmoothScrollLinearLayoutManager?
layoutManager?.scrollToPositionWithOffset(0, 0) layoutManager?.scrollToPositionWithOffset(0, 0)
return true return true
} }
}) })
} }
return true
}
private fun showSearchOrToolbar() {
if (TextUtils.isEmpty(searchQuery)) {
val showSearchBar = appBarLayoutType == AppBarLayoutType.SEARCH_BAR
if (appBarLayoutType == AppBarLayoutType.EMPTY) {
hideBars()
} else {
if (showSearchBar) {
showSearchBar()
} else {
showToolbar()
}
colorizeStatusBar(showSearchBar, this, resources)
}
colorizeNavigationBar(this, resources)
}
}
private fun showSearchBar() {
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
binding.searchToolbar.visibility = View.VISIBLE
binding.searchText.hint = getString(R.string.appbar_search_in, getString(R.string.nc_app_product_name))
binding.conversationListToolbar.visibility = View.GONE
// layoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout
// .LayoutParams.SCROLL_FLAG_SNAP | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
layoutParams.scrollFlags = 0
binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
binding.conversationListAppbar.context,
R.animator.appbar_elevation_off
)
binding.searchToolbar.layoutParams = layoutParams
}
private fun showToolbar() {
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
binding.searchToolbar.visibility = View.GONE
binding.searchToolbar.visibility = View.VISIBLE
viewThemeUtils.material.colorToolbarOverflowIcon(binding.conversationListToolbar)
layoutParams.scrollFlags = 0
binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
binding.conversationListAppbar.context,
R.animator.appbar_elevation_on
)
binding.conversationListToolbar.layoutParams = layoutParams
}
private fun hideBars() {
binding.conversationListToolbar.visibility = View.GONE
binding.searchToolbar.visibility = View.GONE
}
private fun hideSearchBar() {
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
binding.searchToolbar.visibility = View.GONE
binding.conversationListToolbar.visibility = View.VISIBLE
layoutParams.scrollFlags = 0
binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
binding.conversationListAppbar.context,
R.animator.appbar_elevation_on
)
}
private fun colorizeStatusBar(showSearchBar: Boolean, activity: Activity?, resources: Resources?) {
if (activity != null && resources != null) {
if (showSearchBar) {
viewThemeUtils.platform.resetStatusBar(activity)
} else {
viewThemeUtils.platform.themeStatusBar(activity, binding.root)
}
}
}
private fun colorizeNavigationBar(activity: Activity?, resources: Resources?) {
if (activity != null && resources != null) {
DisplayUtils.applyColorToNavigationBar(
activity.window,
ResourcesCompat.getColor(resources, R.color.bg_default, null)
)
}
} }
private fun hasActivityActionSendIntent(): Boolean { private fun hasActivityActionSendIntent(): Boolean {
return if (activity != null) { return Intent.ACTION_SEND == intent.action || Intent.ACTION_SEND_MULTIPLE == intent.action
Intent.ACTION_SEND == activity!!.intent.action || Intent.ACTION_SEND_MULTIPLE == activity!!.intent.action
} else {
false
}
} }
override fun showSearchOrToolbar() { private fun showSearchView(searchView: SearchView?, searchItem: MenuItem?) {
if (TextUtils.isEmpty(searchQuery)) { binding.conversationListAppbar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
super.showSearchOrToolbar() binding.conversationListAppbar.context,
}
}
private fun showSearchView(activity: MainActivity, searchView: SearchView?, searchItem: MenuItem?) {
activity.binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
activity.binding.appBar.context,
R.animator.appbar_elevation_on R.animator.appbar_elevation_on
) )
activity.binding.toolbar.visibility = View.VISIBLE binding.conversationListToolbar.visibility = View.VISIBLE
activity.binding.searchToolbar.visibility = View.GONE binding.searchToolbar.visibility = View.GONE
searchItem!!.expandActionView() searchItem!!.expandActionView()
} }
@ -499,10 +574,11 @@ class ConversationsListController(bundle: Bundle) :
// This is invoked asynchronously, when server returns a response the view might have been // This is invoked asynchronously, when server returns a response the view might have been
// unbound in the meantime. Check if the view is still there. // unbound in the meantime. Check if the view is still there.
// FIXME - does it make sense to update internal data structures even when view has been unbound? // FIXME - does it make sense to update internal data structures even when view has been unbound?
if (view == null) { // if (view == null) {
Log.d(TAG, "fetchData - getRooms - view is not bound: $startNanoTime") // Log.d(TAG, "fetchData - getRooms - view is not bound: $startNanoTime")
return@subscribe // return@subscribe
} // }
if (adapterWasNull) { if (adapterWasNull) {
adapterWasNull = false adapterWasNull = false
binding?.loadingContent?.visibility = View.GONE binding?.loadingContent?.visibility = View.GONE
@ -548,8 +624,8 @@ class ConversationsListController(bundle: Bundle) :
} }
private fun addToConversationItems(conversation: Conversation) { private fun addToConversationItems(conversation: Conversation) {
if (bundle.containsKey(KEY_FORWARD_HIDE_SOURCE_ROOM) && conversation.roomId == if (intent.getStringExtra(KEY_FORWARD_HIDE_SOURCE_ROOM) != null &&
bundle.getString(KEY_FORWARD_HIDE_SOURCE_ROOM) intent.getStringExtra(KEY_FORWARD_HIDE_SOURCE_ROOM) == conversation.roomId
) { ) {
return return
} }
@ -566,23 +642,22 @@ class ConversationsListController(bundle: Bundle) :
genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils) genericTextHeaderItem = GenericTextHeaderItem(headerTitle, viewThemeUtils)
callHeaderItems[headerTitle] = genericTextHeaderItem callHeaderItems[headerTitle] = genericTextHeaderItem
} }
if (activity != null) {
val conversationItem = ConversationItem( val conversationItem = ConversationItem(
conversation, conversation,
currentUser!!, currentUser!!,
activity!!, this,
viewThemeUtils viewThemeUtils
) )
conversationItems.add(conversationItem) conversationItems.add(conversationItem)
val conversationItemWithHeader = ConversationItem( val conversationItemWithHeader = ConversationItem(
conversation, conversation,
currentUser!!, currentUser!!,
activity!!, this,
callHeaderItems[headerTitle], callHeaderItems[headerTitle],
viewThemeUtils viewThemeUtils
) )
conversationItemsWithHeader.add(conversationItemWithHeader) conversationItemsWithHeader.add(conversationItemWithHeader)
}
} }
private fun showErrorDialog() { private fun showErrorDialog() {
@ -639,7 +714,7 @@ class ConversationsListController(bundle: Bundle) :
val conversationItem = ConversationItem( val conversationItem = ConversationItem(
conversation, conversation,
currentUser!!, currentUser!!,
activity!!, this,
callHeaderItems[headerTitle], callHeaderItems[headerTitle],
viewThemeUtils viewThemeUtils
) )
@ -659,30 +734,18 @@ class ConversationsListController(bundle: Bundle) :
private fun handleHttpExceptions(throwable: Throwable) { private fun handleHttpExceptions(throwable: Throwable) {
if (throwable is HttpException) { if (throwable is HttpException) {
when (throwable.code()) { when (throwable.code()) {
HTTP_UNAUTHORIZED -> if (parentController != null && parentController!!.router != null) { HTTP_UNAUTHORIZED -> showUnauthorizedDialog()
Log.d(TAG, "Starting reauth webview via getParentController()") else -> {
parentController!!.router.pushController( Log.e(TAG, "Http exception in ConversationListActivity", throwable)
RouterTransaction.with( Toast.makeText(context, R.string.nc_common_error_sorry, Toast.LENGTH_LONG).show()
WebViewLoginController(
currentUser!!.baseUrl,
true
)
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
} else {
Log.d(TAG, "Starting reauth webview via ConversationsListController")
showUnauthorizedDialog()
} }
else -> {}
} }
} }
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
private fun prepareViews() { private fun prepareViews() {
layoutManager = SmoothScrollLinearLayoutManager(Objects.requireNonNull(activity)) layoutManager = SmoothScrollLinearLayoutManager(this)
binding?.recyclerView?.layoutManager = layoutManager binding?.recyclerView?.layoutManager = layoutManager
binding?.recyclerView?.setHasFixedSize(true) binding?.recyclerView?.setHasFixedSize(true)
binding?.recyclerView?.adapter = adapter binding?.recyclerView?.adapter = adapter
@ -695,8 +758,8 @@ class ConversationsListController(bundle: Bundle) :
} }
}) })
binding?.recyclerView?.setOnTouchListener { v: View, _: MotionEvent? -> binding?.recyclerView?.setOnTouchListener { v: View, _: MotionEvent? ->
if (isAttached && (!isBeingDestroyed || !isDestroyed)) { if (!isDestroyed) {
val imm = activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(v.windowToken, 0) imm.hideSoftInputFromWindow(v.windowToken, 0)
} }
false false
@ -709,21 +772,17 @@ class ConversationsListController(bundle: Bundle) :
showNewConversationsScreen() showNewConversationsScreen()
} }
binding?.floatingActionButton?.let { viewThemeUtils.material.themeFAB(it) } binding?.floatingActionButton?.let { viewThemeUtils.material.themeFAB(it) }
if (activity != null && activity is MainActivity) {
val activity = activity as MainActivity? binding.switchAccountButton.setOnClickListener {
activity!!.binding.switchAccountButton.setOnClickListener { if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) {
if (resources != null && resources!!.getBoolean(R.bool.multiaccount_support)) { val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance()
val newFragment: DialogFragment = ChooseAccountDialogFragment.newInstance() newFragment.show(supportFragmentManager, ChooseAccountDialogFragment.TAG)
newFragment.show( } else {
(getActivity() as MainActivity?)!!.supportFragmentManager, val intent = Intent(context, SettingsActivity::class.java)
ChooseAccountDialogFragment.TAG startActivity(intent)
)
} else {
val intent = Intent(context, SettingsActivity::class.java)
startActivity(intent)
}
} }
} }
binding?.newMentionPopupBubble?.hide() binding?.newMentionPopupBubble?.hide()
binding?.newMentionPopupBubble?.setPopupBubbleListener { binding?.newMentionPopupBubble?.setPopupBubbleListener {
binding?.recyclerView?.smoothScrollToPosition( binding?.recyclerView?.smoothScrollToPosition(
@ -786,17 +845,19 @@ class ConversationsListController(bundle: Bundle) :
} }
} }
public override fun onSaveViewState(view: View, outState: Bundle) { override fun onSaveInstanceState(bundle: Bundle) {
super.onSaveInstanceState(bundle)
if (searchView != null && !TextUtils.isEmpty(searchView!!.query)) { if (searchView != null && !TextUtils.isEmpty(searchView!!.query)) {
outState.putString(KEY_SEARCH_QUERY, searchView!!.query.toString()) bundle.putString(KEY_SEARCH_QUERY, searchView!!.query.toString())
} }
super.onSaveViewState(view, outState)
} }
public override fun onRestoreViewState(view: View, savedViewState: Bundle) { override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreViewState(view, savedViewState) super.onRestoreInstanceState(savedInstanceState)
if (savedViewState.containsKey(KEY_SEARCH_QUERY)) {
searchQuery = savedViewState.getString(KEY_SEARCH_QUERY, "") if (savedInstanceState.containsKey(KEY_SEARCH_QUERY)) {
searchQuery = savedInstanceState.getString(KEY_SEARCH_QUERY, "")
} }
} }
@ -906,7 +967,7 @@ class ConversationsListController(bundle: Bundle) :
@Suppress("Detekt.ComplexMethod") @Suppress("Detekt.ComplexMethod")
private fun handleConversation(conversation: Conversation?) { private fun handleConversation(conversation: Conversation?) {
selectedConversation = conversation selectedConversation = conversation
if (selectedConversation != null && activity != null) { if (selectedConversation != null) {
val hasChatPermission = ParticipantPermissions(currentUser!!, selectedConversation!!).hasChatPermission() val hasChatPermission = ParticipantPermissions(currentUser!!, selectedConversation!!).hasChatPermission()
if (showShareToScreen) { if (showShareToScreen) {
if (hasChatPermission && if (hasChatPermission &&
@ -919,7 +980,7 @@ class ConversationsListController(bundle: Bundle) :
} }
} else if (forwardMessage) { } else if (forwardMessage) {
if (hasChatPermission && !isReadOnlyConversation(selectedConversation!!)) { if (hasChatPermission && !isReadOnlyConversation(selectedConversation!!)) {
openConversation(bundle.getString(KEY_FORWARD_MSG_TEXT)) openConversation(intent.getStringExtra(KEY_FORWARD_MSG_TEXT))
forwardMessage = false forwardMessage = false
} else { } else {
Toast.makeText(context, R.string.send_to_forbidden, Toast.LENGTH_LONG).show() Toast.makeText(context, R.string.send_to_forbidden, Toast.LENGTH_LONG).show()
@ -1001,7 +1062,7 @@ class ConversationsListController(bundle: Bundle) :
} }
private fun clearIntentAction() { private fun clearIntentAction() {
activity!!.intent.action = "" intent.action = ""
} }
override fun onItemLongClick(position: Int) { override fun onItemLongClick(position: Int) {
@ -1012,7 +1073,7 @@ class ConversationsListController(bundle: Bundle) :
if (clickedItem != null) { if (clickedItem != null) {
val conversation = (clickedItem as ConversationItem).model val conversation = (clickedItem as ConversationItem).model
conversationsListBottomDialog = ConversationsListBottomDialog( conversationsListBottomDialog = ConversationsListBottomDialog(
activity!!, this,
this, this,
userManager.currentUser.blockingGet(), userManager.currentUser.blockingGet(),
conversation conversation
@ -1025,8 +1086,7 @@ class ConversationsListController(bundle: Bundle) :
@Suppress("Detekt.TooGenericExceptionCaught") @Suppress("Detekt.TooGenericExceptionCaught")
private fun collectDataFromIntent() { private fun collectDataFromIntent() {
filesToShare = ArrayList() filesToShare = ArrayList()
if (activity != null && activity!!.intent != null) { if (intent != null) {
val intent = activity!!.intent
if (Intent.ACTION_SEND == intent.action || Intent.ACTION_SEND_MULTIPLE == intent.action) { if (Intent.ACTION_SEND == intent.action || Intent.ACTION_SEND_MULTIPLE == intent.action) {
try { try {
val mimeType = intent.type val mimeType = intent.type
@ -1099,6 +1159,7 @@ class ConversationsListController(bundle: Bundle) :
} }
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION && if (requestCode == UploadAndShareFilesWorker.REQUEST_PERMISSION &&
grantResults.isNotEmpty() && grantResults.isNotEmpty() &&
grantResults[0] == PackageManager.PERMISSION_GRANTED grantResults[0] == PackageManager.PERMISSION_GRANTED
@ -1132,13 +1193,6 @@ class ConversationsListController(bundle: Bundle) :
bundle.putString(BundleKeys.KEY_MESSAGE_ID, selectedMessageId) bundle.putString(BundleKeys.KEY_MESSAGE_ID, selectedMessageId)
selectedMessageId = null selectedMessageId = null
} }
// remapChatController(
// router,
// currentUser!!.id!!,
// selectedConversation!!.token!!,
// bundle,
// false
// )
val intent = Intent(context, ChatActivity::class.java) val intent = Intent(context, ChatActivity::class.java)
intent.putExtras(bundle) intent.putExtras(bundle)
@ -1171,8 +1225,7 @@ class ConversationsListController(bundle: Bundle) :
override fun showDeleteConversationDialog(bundle: Bundle) { override fun showDeleteConversationDialog(bundle: Bundle) {
conversationMenuBundle = bundle conversationMenuBundle = bundle
if (activity != null && if (conversationMenuBundle != null &&
conversationMenuBundle != null &&
isInternalUserEqualsCurrentUser(currentUser, conversationMenuBundle) isInternalUserEqualsCurrentUser(currentUser, conversationMenuBundle)
) { ) {
val conversation = Parcels.unwrap<Conversation>(conversationMenuBundle!!.getParcelable(KEY_ROOM)) val conversation = Parcels.unwrap<Conversation>(conversationMenuBundle!!.getParcelable(KEY_ROOM))
@ -1216,53 +1269,47 @@ class ConversationsListController(bundle: Bundle) :
} }
private fun showUnauthorizedDialog() { private fun showUnauthorizedDialog() {
if (activity != null) { binding?.floatingActionButton?.let {
binding?.floatingActionButton?.let { val dialogBuilder = MaterialAlertDialogBuilder(it.context)
val dialogBuilder = MaterialAlertDialogBuilder(it.context) .setIcon(
.setIcon( viewThemeUtils.dialog.colorMaterialAlertDialogIcon(
viewThemeUtils.dialog.colorMaterialAlertDialogIcon( context,
context, R.drawable.ic_delete_black_24dp
R.drawable.ic_delete_black_24dp
)
) )
.setTitle(R.string.nc_dialog_invalid_password)
.setMessage(R.string.nc_dialog_reauth_or_delete)
.setCancelable(false)
.setPositiveButton(R.string.nc_delete) { _, _ ->
val otherUserExists = userManager
.scheduleUserForDeletionWithId(currentUser!!.id!!)
.blockingGet()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
WorkManager.getInstance().enqueue(accountRemovalWork)
if (otherUserExists && view != null) {
onViewBound(view!!)
onAttach(view!!)
} else if (!otherUserExists) {
router.setRoot(
RouterTransaction.with(ServerSelectionController())
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
}
.setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
router.pushController(
RouterTransaction.with(
WebViewLoginController(currentUser!!.baseUrl, true)
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
}
viewThemeUtils.dialog
.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
) )
} .setTitle(R.string.nc_dialog_invalid_password)
.setMessage(R.string.nc_dialog_reauth_or_delete)
.setCancelable(false)
.setPositiveButton(R.string.nc_delete) { _, _ ->
val otherUserExists = userManager
.scheduleUserForDeletionWithId(currentUser!!.id!!)
.blockingGet()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
WorkManager.getInstance().enqueue(accountRemovalWork)
if (otherUserExists) {
finish()
startActivity(intent)
} else if (!otherUserExists) {
Log.d(TAG, "No other users found. AccountRemovalWorker will restart the app.")
}
}
.setNegativeButton(R.string.nc_settings_reauthorize) { _, _ ->
// TODO
// router.pushController(
// RouterTransaction.with(
// WebViewLoginController(currentUser!!.baseUrl, true)
// )
// .pushChangeHandler(VerticalChangeHandler())
// .popChangeHandler(VerticalChangeHandler())
// )
}
viewThemeUtils.dialog.colorMaterialAlertDialogBackground(it.context, dialogBuilder)
val dialog = dialogBuilder.show()
viewThemeUtils.platform.colorTextButtons(
dialog.getButton(AlertDialog.BUTTON_POSITIVE),
dialog.getButton(AlertDialog.BUTTON_NEGATIVE)
)
} }
} }
@ -1279,25 +1326,20 @@ class ConversationsListController(bundle: Bundle) :
.blockingGet() .blockingGet()
val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build() val accountRemovalWork = OneTimeWorkRequest.Builder(AccountRemovalWorker::class.java).build()
WorkManager.getInstance().enqueue(accountRemovalWork) WorkManager.getInstance().enqueue(accountRemovalWork)
if (otherUserExists && view != null) { if (otherUserExists) {
onViewBound(view!!) finish()
onAttach(view!!) startActivity(intent)
} else if (!otherUserExists) { } else if (!otherUserExists) {
router.setRoot( restartApp(this)
RouterTransaction.with(
ServerSelectionController()
)
.pushChangeHandler(VerticalChangeHandler())
.popChangeHandler(VerticalChangeHandler())
)
} }
} }
.setNegativeButton(R.string.nc_cancel) { _, _ -> .setNegativeButton(R.string.nc_cancel) { _, _ ->
if (userManager.users.blockingGet().isNotEmpty()) { if (userManager.users.blockingGet().isNotEmpty()) {
router.pushController(RouterTransaction.with(SwitchAccountController())) // TODO
// router.pushController(RouterTransaction.with(SwitchAccountController()))
} else { } else {
activity!!.finishAffinity() finishAffinity()
activity!!.finish() finish()
} }
} }
@ -1310,6 +1352,15 @@ class ConversationsListController(bundle: Bundle) :
} }
} }
fun restartApp(context: Context) {
val packageManager = context.packageManager
val intent = packageManager.getLaunchIntentForPackage(context.packageName)
val componentName = intent!!.component
val mainIntent = Intent.makeRestartActivityTask(componentName)
context.startActivity(mainIntent)
Runtime.getRuntime().exit(0)
}
private fun deleteConversation(data: Data) { private fun deleteConversation(data: Data) {
val deleteConversationWorker = val deleteConversationWorker =
OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data).build() OneTimeWorkRequest.Builder(DeleteConversationWorker::class.java).setInputData(data).build()
@ -1351,6 +1402,13 @@ class ConversationsListController(bundle: Bundle) :
showErrorDialog() showErrorDialog()
} }
override fun onBackPressed() {
super.onBackPressed()
// TODO: replace this when conductor is removed. For now it avoids to load the MainActiviy which has no UI.
finishAffinity()
}
companion object { companion object {
const val TAG = "ConvListController" const val TAG = "ConvListController"
const val UNREAD_BUBBLE_DELAY = 2500 const val UNREAD_BUBBLE_DELAY = 2500
@ -1360,10 +1418,4 @@ class ConversationsListController(bundle: Bundle) :
const val SEARCH_MIN_CHARS = 2 const val SEARCH_MIN_CHARS = 2
const val HTTP_UNAUTHORIZED = 401 const val HTTP_UNAUTHORIZED = 401
} }
init {
setHasOptionsMenu(true)
forwardMessage = bundle.getBoolean(KEY_FORWARD_MSG_FLAG)
this.bundle = bundle
}
} }

View File

@ -38,7 +38,7 @@ import com.nextcloud.talk.activities.BaseActivity
import com.nextcloud.talk.adapters.items.LoadMoreResultsItem import com.nextcloud.talk.adapters.items.LoadMoreResultsItem
import com.nextcloud.talk.adapters.items.MessageResultItem import com.nextcloud.talk.adapters.items.MessageResultItem
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.ConversationsListController import com.nextcloud.talk.conversationlist.ConversationsListActivity
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.ActivityMessageSearchBinding import com.nextcloud.talk.databinding.ActivityMessageSearchBinding
import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.DisplayUtils
@ -241,7 +241,7 @@ class MessageSearchActivity : BaseActivity() {
when { when {
TextUtils.isEmpty(query) -> Observable.empty() TextUtils.isEmpty(query) -> Observable.empty()
else -> Observable.timer( else -> Observable.timer(
ConversationsListController.SEARCH_DEBOUNCE_INTERVAL_MS.toLong(), ConversationsListActivity.SEARCH_DEBOUNCE_INTERVAL_MS.toLong(),
TimeUnit.MILLISECONDS TimeUnit.MILLISECONDS
) )
} }

View File

@ -26,6 +26,7 @@ package com.nextcloud.talk.ui.dialog;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Dialog; import android.app.Dialog;
import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
@ -34,16 +35,17 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.google.android.material.dialog.MaterialAlertDialogBuilder; import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.nextcloud.talk.activities.MainActivity;
import com.nextcloud.talk.adapters.items.AdvancedUserItem; import com.nextcloud.talk.adapters.items.AdvancedUserItem;
import com.nextcloud.talk.api.NcApi; import com.nextcloud.talk.api.NcApi;
import com.nextcloud.talk.application.NextcloudTalkApplication; import com.nextcloud.talk.application.NextcloudTalkApplication;
import com.nextcloud.talk.conversationlist.ConversationsListActivity;
import com.nextcloud.talk.data.user.model.User; import com.nextcloud.talk.data.user.model.User;
import com.nextcloud.talk.databinding.DialogChooseAccountBinding; import com.nextcloud.talk.databinding.DialogChooseAccountBinding;
import com.nextcloud.talk.extensions.ImageViewExtensionsKt; import com.nextcloud.talk.extensions.ImageViewExtensionsKt;
import com.nextcloud.talk.models.json.participants.Participant; import com.nextcloud.talk.models.json.participants.Participant;
import com.nextcloud.talk.models.json.status.Status; import com.nextcloud.talk.models.json.status.Status;
import com.nextcloud.talk.models.json.status.StatusOverall; import com.nextcloud.talk.models.json.status.StatusOverall;
import com.nextcloud.talk.settings.SettingsActivity;
import com.nextcloud.talk.ui.StatusDrawable; import com.nextcloud.talk.ui.StatusDrawable;
import com.nextcloud.talk.ui.theme.ViewThemeUtils; import com.nextcloud.talk.ui.theme.ViewThemeUtils;
import com.nextcloud.talk.users.UserManager; import com.nextcloud.talk.users.UserManager;
@ -178,16 +180,18 @@ public class ChooseAccountDialogFragment extends DialogFragment {
// Creating listeners for quick-actions // Creating listeners for quick-actions
binding.currentAccount.getRoot().setOnClickListener(v -> dismiss()); binding.currentAccount.getRoot().setOnClickListener(v -> dismiss());
if (getActivity() instanceof MainActivity) {
binding.addAccount.setOnClickListener(v -> { binding.addAccount.setOnClickListener(v -> {
dismiss(); dismiss();
((MainActivity) getActivity()).addAccount(); // TODO
}); // ((MainActivity) getActivity()).addAccount();
binding.manageSettings.setOnClickListener(v -> { });
dismiss(); binding.manageSettings.setOnClickListener(v -> {
((MainActivity) getActivity()).openSettings(); Intent intent = new Intent(getContext(), SettingsActivity.class);
}); startActivity(intent);
} dismiss();
});
binding.setStatus.setOnClickListener(v -> { binding.setStatus.setOnClickListener(v -> {
dismiss(); dismiss();
@ -294,10 +298,14 @@ public class ChooseAccountDialogFragment extends DialogFragment {
if (userManager.setUserAsActive(user).blockingGet()) { if (userManager.setUserAsActive(user).blockingGet()) {
cookieManager.getCookieStore().removeAll(); cookieManager.getCookieStore().removeAll();
if (getActivity() != null) {
getActivity().runOnUiThread( Intent intent = new Intent(getContext(), ConversationsListActivity.class);
() -> ((MainActivity) getActivity()).resetConversationsList()); // TODO: might be better with FLAG_ACTIVITY_SINGLE_TOP instead than FLAG_ACTIVITY_CLEAR_TOP to
} // have a smoother transition. However the handling in onNewIntent() in
// ConversationListActivity must be improved for this.
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
dismiss(); dismiss();
} }
} }

View File

@ -38,7 +38,6 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.controllers.ConversationsListController
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_ADD_FAVORITE
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_MARK_AS_READ
@ -47,6 +46,7 @@ import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_
import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM import com.nextcloud.talk.controllers.bottomsheet.ConversationOperationEnum.OPS_CODE_RENAME_ROOM
import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController import com.nextcloud.talk.controllers.bottomsheet.EntryMenuController
import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController
import com.nextcloud.talk.conversationlist.ConversationsListActivity
import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.data.user.model.User
import com.nextcloud.talk.databinding.DialogConversationOperationsBinding import com.nextcloud.talk.databinding.DialogConversationOperationsBinding
import com.nextcloud.talk.jobs.LeaveConversationWorker import com.nextcloud.talk.jobs.LeaveConversationWorker
@ -64,7 +64,7 @@ import javax.inject.Inject
@AutoInjector(NextcloudTalkApplication::class) @AutoInjector(NextcloudTalkApplication::class)
class ConversationsListBottomDialog( class ConversationsListBottomDialog(
val activity: Activity, val activity: Activity,
val controller: ConversationsListController, val controller: ConversationsListActivity,
val currentUser: User, val currentUser: User,
val conversation: Conversation val conversation: Conversation
) : BottomSheetDialog(activity) { ) : BottomSheetDialog(activity) {

View File

@ -40,87 +40,7 @@
android:windowContentOverlay="@null" android:windowContentOverlay="@null"
app:elevation="0dp"> app:elevation="0dp">
<com.google.android.material.card.MaterialCardView
android:id="@+id/search_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="16dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="1dp"
android:visibility="gone"
app:cardCornerRadius="25dp"
app:cardElevation="2dp"
app:strokeWidth="0dp"
tools:visibility="visible">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/menu_button"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="3dp"
android:layout_height="1dp"
android:layout_marginStart="5dp"
android:contentDescription="@string/nc_action_open_main_menu"
android:visibility="gone"
app:cornerRadius="@dimen/button_corner_radius"
app:icon="@drawable/ic_menu"
app:iconTint="@color/fontAppbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="18dp"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:lines="1"
android:textAlignment="viewStart"
android:textColor="@color/fontSecondaryAppbar"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/menu_button"
app:layout_constraintEnd_toStartOf="@id/rightContainer"
app:layout_constraintTop_toTopOf="parent"
tools:text="Search in Nextcloud" />
<FrameLayout
android:id="@+id/rightContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:minWidth="48dp"
android:layout_centerVertical="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/switch_account_button"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:contentDescription="@string/nc_settings"
android:scaleType="fitCenter"
android:transitionName="userAvatar.transitionTag"
app:cornerRadius="@dimen/button_corner_radius"
app:iconSize="@dimen/avatar_size_app_bar"
app:iconTint="@null"
tools:icon="@drawable/ic_user" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.appbar.MaterialToolbar <com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar" android:id="@+id/toolbar"

View File

@ -25,11 +25,118 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/conversation_list_appbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/bg_default"
android:elevation="0dp"
android:clipChildren="true"
android:clipToPadding="false"
android:windowContentOverlay="@null"
app:elevation="0dp">
<com.google.android.material.card.MaterialCardView
android:id="@+id/search_toolbar"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="16dp"
android:layout_marginTop="5dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="1dp"
android:visibility="gone"
app:cardCornerRadius="25dp"
app:cardElevation="2dp"
app:strokeWidth="0dp"
tools:visibility="visible">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/menu_button"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="3dp"
android:layout_height="1dp"
android:layout_marginStart="5dp"
android:contentDescription="@string/nc_action_open_main_menu"
android:visibility="gone"
app:cornerRadius="@dimen/button_corner_radius"
app:icon="@drawable/ic_menu"
app:iconTint="@color/fontAppbar"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/search_text"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginStart="20dp"
android:layout_marginEnd="18dp"
android:ellipsize="end"
android:gravity="start|center_vertical"
android:lines="1"
android:textAlignment="viewStart"
android:textColor="@color/fontSecondaryAppbar"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/menu_button"
app:layout_constraintEnd_toStartOf="@id/rightContainer"
app:layout_constraintTop_toTopOf="parent"
tools:text="Search in Nextcloud" />
<FrameLayout
android:id="@+id/rightContainer"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:minWidth="48dp"
android:layout_centerVertical="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.button.MaterialButton
android:id="@+id/switch_account_button"
style="@style/Widget.AppTheme.Button.IconButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:contentDescription="@string/nc_settings"
android:scaleType="fitCenter"
android:transitionName="userAvatar.transitionTag"
app:cornerRadius="@dimen/button_corner_radius"
app:iconSize="@dimen/avatar_size_app_bar"
app:iconTint="@null"
tools:icon="@drawable/ic_user" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/conversation_list_toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/appbar"
android:theme="?attr/actionBarPopupTheme"
app:layout_scrollFlags="enterAlwaysCollapsed|noScroll"
app:navigationIconTint="@color/fontAppbar"
app:popupTheme="@style/appActionBarPopupMenu"
app:titleTextColor="@color/fontAppbar"
tools:title="@string/nc_app_product_name" />
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout <LinearLayout
android:id="@+id/loading_content" android:id="@+id/loading_content"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical"
android:layout_marginTop="50dp">
<include layout="@layout/rv_item_conversation_with_last_message_shimmer" /> <include layout="@layout/rv_item_conversation_with_last_message_shimmer" />