ConversationInfoController.kt 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. /*
  2. * Nextcloud Talk application
  3. *
  4. * @author Mario Danic
  5. * Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. package com.nextcloud.talk.controllers
  21. import android.content.Context
  22. import android.graphics.drawable.Drawable
  23. import android.graphics.drawable.LayerDrawable
  24. import android.opengl.Visibility
  25. import android.os.Bundle
  26. import android.text.TextUtils
  27. import android.view.LayoutInflater
  28. import android.view.MenuItem
  29. import android.view.View
  30. import android.view.ViewGroup
  31. import android.widget.ProgressBar
  32. import android.widget.TextView
  33. import androidx.appcompat.widget.SwitchCompat
  34. import androidx.emoji.widget.EmojiTextView
  35. import androidx.recyclerview.widget.RecyclerView
  36. import androidx.work.Data
  37. import androidx.work.OneTimeWorkRequest
  38. import androidx.work.WorkManager
  39. import autodagger.AutoInjector
  40. import butterknife.BindView
  41. import butterknife.OnClick
  42. import com.afollestad.materialdialogs.LayoutMode.WRAP_CONTENT
  43. import com.afollestad.materialdialogs.MaterialDialog
  44. import com.afollestad.materialdialogs.bottomsheets.BottomSheet
  45. import com.afollestad.materialdialogs.datetime.dateTimePicker
  46. import com.afollestad.materialdialogs.list.listItems
  47. import com.bluelinelabs.conductor.RouterTransaction
  48. import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
  49. import com.facebook.drawee.backends.pipeline.Fresco
  50. import com.facebook.drawee.view.SimpleDraweeView
  51. import com.nextcloud.talk.R
  52. import com.nextcloud.talk.adapters.items.UserItem
  53. import com.nextcloud.talk.api.NcApi
  54. import com.nextcloud.talk.application.NextcloudTalkApplication
  55. import com.nextcloud.talk.controllers.base.BaseController
  56. import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
  57. import com.nextcloud.talk.controllers.bottomsheet.items.ListItemWithImage
  58. import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
  59. import com.nextcloud.talk.events.BottomSheetLockEvent
  60. import com.nextcloud.talk.events.EventStatus
  61. import com.nextcloud.talk.jobs.DeleteConversationWorker
  62. import com.nextcloud.talk.jobs.LeaveConversationWorker
  63. import com.nextcloud.talk.models.database.UserEntity
  64. import com.nextcloud.talk.models.json.conversations.Conversation
  65. import com.nextcloud.talk.models.json.conversations.RoomOverall
  66. import com.nextcloud.talk.models.json.converters.EnumNotificationLevelConverter
  67. import com.nextcloud.talk.models.json.generic.GenericOverall
  68. import com.nextcloud.talk.models.json.participants.Participant
  69. import com.nextcloud.talk.models.json.participants.ParticipantsOverall
  70. import com.nextcloud.talk.utils.ApiUtils
  71. import com.nextcloud.talk.utils.DateUtils
  72. import com.nextcloud.talk.utils.DisplayUtils
  73. import com.nextcloud.talk.utils.bundle.BundleKeys
  74. import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
  75. import com.nextcloud.talk.utils.ui.MaterialPreferenceCategoryWithRightLink
  76. import com.yarolegovich.lovelydialog.LovelySaveStateHandler
  77. import com.yarolegovich.lovelydialog.LovelyStandardDialog
  78. import com.yarolegovich.mp.*
  79. import eu.davidea.flexibleadapter.FlexibleAdapter
  80. import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
  81. import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
  82. import io.reactivex.Observer
  83. import io.reactivex.android.schedulers.AndroidSchedulers
  84. import io.reactivex.disposables.Disposable
  85. import io.reactivex.schedulers.Schedulers
  86. import org.greenrobot.eventbus.EventBus
  87. import org.greenrobot.eventbus.Subscribe
  88. import org.greenrobot.eventbus.ThreadMode
  89. import java.util.*
  90. import javax.inject.Inject
  91. @AutoInjector(NextcloudTalkApplication::class)
  92. class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleAdapter.OnItemClickListener {
  93. @BindView(R.id.notification_settings)
  94. lateinit var notificationsPreferenceScreen: MaterialPreferenceScreen
  95. @BindView(R.id.progressBar)
  96. lateinit var progressBar: ProgressBar
  97. @BindView(R.id.conversation_info_message_notifications)
  98. lateinit var messageNotificationLevel: MaterialChoicePreference
  99. @BindView(R.id.webinar_settings)
  100. lateinit var conversationInfoWebinar: MaterialPreferenceScreen
  101. @BindView(R.id.conversation_info_lobby)
  102. lateinit var conversationInfoLobby: MaterialSwitchPreference
  103. @BindView(R.id.conversation_info_name)
  104. lateinit var nameCategoryView: MaterialPreferenceCategory
  105. @BindView(R.id.start_time_preferences)
  106. lateinit var startTimeView: MaterialStandardPreference
  107. @BindView(R.id.avatar_image)
  108. lateinit var conversationAvatarImageView: SimpleDraweeView
  109. @BindView(R.id.display_name_text)
  110. lateinit var conversationDisplayName: EmojiTextView
  111. @BindView(R.id.participants_list_category)
  112. lateinit var participantsListCategory: MaterialPreferenceCategoryWithRightLink
  113. @BindView(R.id.recycler_view)
  114. lateinit var recyclerView: RecyclerView
  115. @BindView(R.id.deleteConversationAction)
  116. lateinit var deleteConversationAction: MaterialStandardPreference
  117. @BindView(R.id.leaveConversationAction)
  118. lateinit var leaveConversationAction: MaterialStandardPreference
  119. @BindView(R.id.ownOptions)
  120. lateinit var ownOptionsCategory: MaterialPreferenceCategory
  121. @BindView(R.id.muteCalls)
  122. lateinit var muteCalls: MaterialSwitchPreference
  123. @BindView(R.id.mpc_action)
  124. lateinit var actionTextView: TextView;
  125. @set:Inject
  126. lateinit var ncApi: NcApi
  127. @set:Inject
  128. lateinit var context: Context
  129. @set:Inject
  130. lateinit var eventBus: EventBus
  131. private val conversationToken: String?
  132. private val conversationUser: UserEntity?
  133. private val credentials: String?
  134. private var roomDisposable: Disposable? = null
  135. private var participantsDisposable: Disposable? = null
  136. private var databaseStorageModule: DatabaseStorageModule? = null
  137. private var conversation: Conversation? = null
  138. private var adapter: FlexibleAdapter<AbstractFlexibleItem<*>>? = null
  139. private var recyclerViewItems: MutableList<AbstractFlexibleItem<*>> = ArrayList()
  140. private var saveStateHandler: LovelySaveStateHandler? = null
  141. private val workerData: Data?
  142. get() {
  143. if (!TextUtils.isEmpty(conversationToken) && conversationUser != null) {
  144. val data = Data.Builder()
  145. data.putString(BundleKeys.KEY_ROOM_TOKEN, conversationToken)
  146. data.putLong(BundleKeys.KEY_INTERNAL_USER_ID, conversationUser.id)
  147. return data.build()
  148. }
  149. return null
  150. }
  151. init {
  152. setHasOptionsMenu(true)
  153. NextcloudTalkApplication.sharedApplication?.componentApplication?.inject(this)
  154. conversationUser = args.getParcelable(BundleKeys.KEY_USER_ENTITY)
  155. conversationToken = args.getString(BundleKeys.KEY_ROOM_TOKEN)
  156. credentials = ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token)
  157. }
  158. override fun onOptionsItemSelected(item: MenuItem): Boolean {
  159. when (item.itemId) {
  160. android.R.id.home -> {
  161. router.popCurrentController()
  162. return true
  163. }
  164. else -> return super.onOptionsItemSelected(item)
  165. }
  166. }
  167. override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
  168. return inflater.inflate(R.layout.controller_conversation_info, container, false)
  169. }
  170. override fun onAttach(view: View) {
  171. super.onAttach(view)
  172. eventBus.register(this)
  173. if (databaseStorageModule == null) {
  174. databaseStorageModule = DatabaseStorageModule(conversationUser!!, conversationToken)
  175. }
  176. notificationsPreferenceScreen.setStorageModule(databaseStorageModule)
  177. conversationInfoWebinar.setStorageModule(databaseStorageModule)
  178. fetchRoomInfo()
  179. }
  180. override fun onViewBound(view: View) {
  181. super.onViewBound(view)
  182. if (saveStateHandler == null) {
  183. saveStateHandler = LovelySaveStateHandler()
  184. }
  185. actionTextView.visibility = View.GONE
  186. }
  187. private fun setupWebinaryView() {
  188. if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") && (conversation!!.type
  189. == Conversation.ConversationType.ROOM_GROUP_CALL || conversation!!.type ==
  190. Conversation.ConversationType.ROOM_PUBLIC_CALL) && conversation!!.canModerate(conversationUser)) {
  191. conversationInfoWebinar.visibility = View.VISIBLE
  192. val isLobbyOpenToModeratorsOnly = conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
  193. (conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
  194. .isChecked = isLobbyOpenToModeratorsOnly
  195. reconfigureLobbyTimerView()
  196. startTimeView.setOnClickListener {
  197. MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
  198. val currentTimeCalendar = Calendar.getInstance()
  199. if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != 0L) {
  200. currentTimeCalendar.timeInMillis = conversation!!.lobbyTimer * 1000
  201. }
  202. dateTimePicker(minDateTime = Calendar.getInstance(), requireFutureDateTime =
  203. true, currentDateTime = currentTimeCalendar, dateTimeCallback = { _,
  204. dateTime ->
  205. reconfigureLobbyTimerView(dateTime)
  206. submitLobbyChanges()
  207. })
  208. }
  209. }
  210. (conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat).setOnCheckedChangeListener { _, _ ->
  211. reconfigureLobbyTimerView()
  212. submitLobbyChanges()
  213. }
  214. } else {
  215. conversationInfoWebinar.visibility = View.GONE
  216. }
  217. }
  218. fun reconfigureLobbyTimerView(dateTime: Calendar? = null) {
  219. val isChecked = (conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat).isChecked
  220. if (dateTime != null && isChecked) {
  221. conversation!!.lobbyTimer = (dateTime.timeInMillis - (dateTime.time.seconds * 1000)) / 1000
  222. } else if (!isChecked) {
  223. conversation!!.lobbyTimer = 0
  224. }
  225. conversation!!.lobbyState = if (isChecked) Conversation.LobbyState
  226. .LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
  227. if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE && conversation!!.lobbyTimer != 0L) {
  228. startTimeView.setSummary(DateUtils.getLocalDateStringFromTimestampForLobby(conversation!!.lobbyTimer))
  229. } else {
  230. startTimeView.setSummary(R.string.nc_manual)
  231. }
  232. if (isChecked) {
  233. startTimeView.visibility = View.VISIBLE
  234. } else {
  235. startTimeView.visibility = View.GONE
  236. }
  237. }
  238. fun submitLobbyChanges() {
  239. val state = if ((conversationInfoLobby.findViewById<View>(R.id
  240. .mp_checkable) as SwitchCompat).isChecked) 1 else 0
  241. ncApi.setLobbyForConversation(ApiUtils.getCredentials(conversationUser!!.username,
  242. conversationUser.token), ApiUtils.getUrlForLobbyForConversation
  243. (conversationUser.baseUrl, conversation!!.token), state, conversation!!.lobbyTimer)
  244. .subscribeOn(Schedulers.io())
  245. .observeOn(AndroidSchedulers.mainThread())
  246. .subscribe(object : Observer<GenericOverall> {
  247. override fun onComplete() {
  248. }
  249. override fun onSubscribe(d: Disposable) {
  250. }
  251. override fun onNext(t: GenericOverall) {
  252. }
  253. override fun onError(e: Throwable) {
  254. }
  255. })
  256. }
  257. private fun showLovelyDialog(dialogId: Int, savedInstanceState: Bundle) {
  258. when (dialogId) {
  259. ID_DELETE_CONVERSATION_DIALOG -> showDeleteConversationDialog(savedInstanceState)
  260. else -> {
  261. }
  262. }
  263. }
  264. @Subscribe(threadMode = ThreadMode.MAIN)
  265. fun onMessageEvent(eventStatus: EventStatus) {
  266. getListOfParticipants()
  267. }
  268. override fun onDetach(view: View) {
  269. super.onDetach(view)
  270. eventBus.unregister(this)
  271. }
  272. private fun showDeleteConversationDialog(savedInstanceState: Bundle?) {
  273. if (activity != null) {
  274. LovelyStandardDialog(activity, LovelyStandardDialog.ButtonLayout.HORIZONTAL)
  275. .setTopColorRes(R.color.nc_darkRed)
  276. .setIcon(DisplayUtils.getTintedDrawable(context!!.resources,
  277. R.drawable.ic_delete_black_24dp, R.color.bg_default))
  278. .setPositiveButtonColor(context!!.resources.getColor(R.color.nc_darkRed))
  279. .setTitle(R.string.nc_delete_call)
  280. .setMessage(conversation!!.deleteWarningMessage)
  281. .setPositiveButton(R.string.nc_delete) { deleteConversation() }
  282. .setNegativeButton(R.string.nc_cancel, null)
  283. .setInstanceStateHandler(ID_DELETE_CONVERSATION_DIALOG, saveStateHandler!!)
  284. .setSavedInstanceState(savedInstanceState)
  285. .show()
  286. }
  287. }
  288. override fun onSaveViewState(view: View, outState: Bundle) {
  289. saveStateHandler!!.saveInstanceState(outState)
  290. super.onSaveViewState(view, outState)
  291. }
  292. override fun onRestoreViewState(view: View, savedViewState: Bundle) {
  293. super.onRestoreViewState(view, savedViewState)
  294. if (LovelySaveStateHandler.wasDialogOnScreen(savedViewState)) {
  295. //Dialog won't be restarted automatically, so we need to call this method.
  296. //Each dialog knows how to restore its state
  297. showLovelyDialog(LovelySaveStateHandler.getSavedDialogId(savedViewState), savedViewState)
  298. }
  299. }
  300. private fun setupAdapter() {
  301. if (activity != null) {
  302. if (adapter == null) {
  303. adapter = FlexibleAdapter(recyclerViewItems, activity, true)
  304. }
  305. val layoutManager = SmoothScrollLinearLayoutManager(activity)
  306. recyclerView.layoutManager = layoutManager
  307. recyclerView.setHasFixedSize(true)
  308. recyclerView.adapter = adapter
  309. adapter!!.addListener(this)
  310. actionTextView.setOnClickListener {
  311. val bundle = Bundle()
  312. val existingParticipantsId = arrayListOf<String>()
  313. recyclerViewItems.forEach {
  314. val userItem = it as UserItem
  315. existingParticipantsId.add(userItem.model.userId)
  316. }
  317. bundle.putBoolean(BundleKeys.KEY_ADD_PARTICIPANTS, true);
  318. bundle.putStringArrayList(BundleKeys.KEY_EXISTING_PARTICIPANTS, existingParticipantsId)
  319. bundle.putString(BundleKeys.KEY_TOKEN, conversation!!.token)
  320. getRouter().pushController((RouterTransaction.with(ContactsController(bundle))
  321. .pushChangeHandler(HorizontalChangeHandler())
  322. .popChangeHandler(HorizontalChangeHandler())));
  323. }
  324. }
  325. }
  326. private fun handleParticipants(participants: List<Participant>) {
  327. var userItem: UserItem
  328. var participant: Participant
  329. recyclerViewItems = ArrayList()
  330. var ownUserItem: UserItem? = null
  331. for (i in participants.indices) {
  332. participant = participants[i]
  333. userItem = UserItem(participant, conversationUser, null)
  334. userItem.isOnline = !participant.sessionId.equals("0")
  335. if (!TextUtils.isEmpty(participant.userId) && participant.userId == conversationUser!!.userId) {
  336. ownUserItem = userItem
  337. ownUserItem.model.sessionId = "-1"
  338. ownUserItem.isOnline = true
  339. } else {
  340. recyclerViewItems.add(userItem)
  341. }
  342. }
  343. if (ownUserItem != null) {
  344. recyclerViewItems.add(0, ownUserItem)
  345. }
  346. setupAdapter()
  347. participantsListCategory.visibility = View.VISIBLE
  348. adapter!!.updateDataSet(recyclerViewItems)
  349. }
  350. override fun getTitle(): String? {
  351. return resources!!.getString(R.string.nc_conversation_menu_conversation_info)
  352. }
  353. private fun getListOfParticipants() {
  354. ncApi.getPeersForCall(credentials, ApiUtils.getUrlForParticipants(conversationUser!!.baseUrl, conversationToken))
  355. .subscribeOn(Schedulers.io())
  356. .observeOn(AndroidSchedulers.mainThread())
  357. .subscribe(object : Observer<ParticipantsOverall> {
  358. override fun onSubscribe(d: Disposable) {
  359. participantsDisposable = d
  360. }
  361. override fun onNext(participantsOverall: ParticipantsOverall) {
  362. handleParticipants(participantsOverall.ocs.data)
  363. }
  364. override fun onError(e: Throwable) {
  365. }
  366. override fun onComplete() {
  367. participantsDisposable!!.dispose()
  368. }
  369. })
  370. }
  371. @OnClick(R.id.leaveConversationAction)
  372. internal fun leaveConversation() {
  373. workerData?.let {
  374. WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
  375. (LeaveConversationWorker::class
  376. .java).setInputData(it).build()
  377. )
  378. popTwoLastControllers()
  379. }
  380. }
  381. private fun deleteConversation() {
  382. workerData?.let {
  383. WorkManager.getInstance().enqueue(OneTimeWorkRequest.Builder
  384. (DeleteConversationWorker::class.java).setInputData(it).build())
  385. popTwoLastControllers()
  386. }
  387. }
  388. @OnClick(R.id.deleteConversationAction)
  389. internal fun deleteConversationClick() {
  390. showDeleteConversationDialog(null)
  391. }
  392. private fun popTwoLastControllers() {
  393. var backstack = router.backstack
  394. backstack = backstack.subList(0, backstack.size - 2)
  395. router.setBackstack(backstack, HorizontalChangeHandler())
  396. }
  397. private fun fetchRoomInfo() {
  398. ncApi.getRoom(credentials, ApiUtils.getRoom(conversationUser!!.baseUrl, conversationToken))
  399. .subscribeOn(Schedulers.io())
  400. .observeOn(AndroidSchedulers.mainThread())
  401. .subscribe(object : Observer<RoomOverall> {
  402. override fun onSubscribe(d: Disposable) {
  403. roomDisposable = d
  404. }
  405. override fun onNext(roomOverall: RoomOverall) {
  406. conversation = roomOverall.ocs.data
  407. val conversationCopy = conversation
  408. if (conversationCopy!!.canModerate(conversationUser)) {
  409. actionTextView.visibility = View.VISIBLE
  410. } else {
  411. actionTextView.visibility = View.GONE
  412. }
  413. if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
  414. ownOptionsCategory.visibility = View.VISIBLE
  415. setupWebinaryView()
  416. if (!conversation!!.canLeave(conversationUser)) {
  417. leaveConversationAction.visibility = View.GONE
  418. } else {
  419. leaveConversationAction.visibility = View.VISIBLE
  420. }
  421. if (!conversation!!.canModerate(conversationUser)) {
  422. deleteConversationAction.visibility = View.GONE
  423. } else {
  424. deleteConversationAction.visibility = View.VISIBLE
  425. }
  426. if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
  427. muteCalls.visibility = View.GONE
  428. }
  429. getListOfParticipants()
  430. progressBar.visibility = View.GONE
  431. nameCategoryView.visibility = View.VISIBLE
  432. conversationDisplayName.text = conversation!!.displayName
  433. loadConversationAvatar()
  434. adjustNotificationLevelUI()
  435. notificationsPreferenceScreen.visibility = View.VISIBLE
  436. }
  437. }
  438. override fun onError(e: Throwable) {
  439. }
  440. override fun onComplete() {
  441. roomDisposable!!.dispose()
  442. }
  443. })
  444. }
  445. private fun adjustNotificationLevelUI() {
  446. if (conversation != null) {
  447. if (conversationUser != null && conversationUser.hasSpreedFeatureCapability("notification-levels")) {
  448. messageNotificationLevel.isEnabled = true
  449. messageNotificationLevel.alpha = 1.0f
  450. if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) {
  451. val stringValue: String = when (EnumNotificationLevelConverter().convertToInt(conversation!!.notificationLevel)) {
  452. 1 -> "always"
  453. 2 -> "mention"
  454. 3 -> "never"
  455. else -> "mention"
  456. }
  457. messageNotificationLevel.value = stringValue
  458. } else {
  459. setProperNotificationValue(conversation)
  460. }
  461. } else {
  462. messageNotificationLevel.isEnabled = false
  463. messageNotificationLevel.alpha = 0.38f
  464. setProperNotificationValue(conversation)
  465. }
  466. }
  467. }
  468. private fun setProperNotificationValue(conversation: Conversation?) {
  469. if (conversation!!.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
  470. // hack to see if we get mentioned always or just on mention
  471. if (conversationUser!!.hasSpreedFeatureCapability("mention-flag")) {
  472. messageNotificationLevel.value = "always"
  473. } else {
  474. messageNotificationLevel.value = "mention"
  475. }
  476. } else {
  477. messageNotificationLevel.value = "mention"
  478. }
  479. }
  480. private fun loadConversationAvatar() {
  481. when (conversation!!.type) {
  482. Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty
  483. (conversation!!.name)) {
  484. val draweeController = Fresco.newDraweeControllerBuilder()
  485. .setOldController(conversationAvatarImageView.controller)
  486. .setAutoPlayAnimations(true)
  487. .setImageRequest(DisplayUtils.getImageRequestForUrl(ApiUtils.getUrlForAvatarWithName(conversationUser!!.baseUrl,
  488. conversation!!.name, R.dimen.avatar_size_big), null))
  489. .build()
  490. conversationAvatarImageView.controller = draweeController
  491. }
  492. Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
  493. .getRoundedBitmapDrawableFromVectorDrawableResource(resources,
  494. R.drawable.ic_people_group_white_24px))
  495. Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils
  496. .getRoundedBitmapDrawableFromVectorDrawableResource(resources,
  497. R.drawable.ic_link_white_24px))
  498. Conversation.ConversationType.ROOM_SYSTEM -> {
  499. val layers = arrayOfNulls<Drawable>(2)
  500. layers[0] = context.getDrawable(R.drawable.ic_launcher_background)
  501. layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground)
  502. val layerDrawable = LayerDrawable(layers)
  503. conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable))
  504. }
  505. else -> {
  506. }
  507. }
  508. }
  509. override fun onItemClick(view: View?, position: Int): Boolean {
  510. val userItem = adapter?.getItem(position) as UserItem
  511. val participant = userItem.model
  512. if (participant.userId != conversationUser!!.userId) {
  513. var items = mutableListOf(
  514. BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
  515. BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
  516. BasicListItemWithImage(R.drawable.ic_delete_grey600_24dp,
  517. context.getString(R.string.nc_remove_participant))
  518. )
  519. if (!conversation!!.canModerate(conversationUser)) {
  520. items = mutableListOf()
  521. } else {
  522. if (participant.type == Participant.ParticipantType.MODERATOR || participant.type == Participant.ParticipantType.OWNER) {
  523. items.removeAt(0)
  524. } else if (participant.type == Participant.ParticipantType.USER) {
  525. items.removeAt(1)
  526. }
  527. }
  528. if (items.isNotEmpty()) {
  529. MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
  530. cornerRadius(res = R.dimen.corner_radius)
  531. title(text = participant.displayName)
  532. listItemsWithImage(items = items) { dialog, index, _ ->
  533. if (index == 0) {
  534. if (participant.type == Participant.ParticipantType.MODERATOR) {
  535. ncApi.demoteModeratorToUser(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
  536. .subscribeOn(Schedulers.io())
  537. .observeOn(AndroidSchedulers.mainThread())
  538. .subscribe {
  539. getListOfParticipants()
  540. }
  541. } else if (participant.type == Participant.ParticipantType.USER) {
  542. ncApi.promoteUserToModerator(credentials, ApiUtils.getUrlForModerators(conversationUser.baseUrl, conversation!!.token), participant.userId)
  543. .subscribeOn(Schedulers.io())
  544. .observeOn(AndroidSchedulers.mainThread())
  545. .subscribe {
  546. getListOfParticipants()
  547. }
  548. }
  549. } else if (index == 1) {
  550. if (participant.type == Participant.ParticipantType.GUEST ||
  551. participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK) {
  552. ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, true), participant.sessionId)
  553. .subscribeOn(Schedulers.io())
  554. .observeOn(AndroidSchedulers.mainThread())
  555. .subscribe {
  556. getListOfParticipants()
  557. }
  558. } else {
  559. ncApi.removeParticipantFromConversation(credentials, ApiUtils.getUrlForRemovingParticipantFromConversation(conversationUser.baseUrl, conversation!!.token, false), participant.userId)
  560. .subscribeOn(Schedulers.io())
  561. .observeOn(AndroidSchedulers.mainThread())
  562. .subscribe {
  563. getListOfParticipants()
  564. // get participants again
  565. }
  566. }
  567. }
  568. }
  569. }
  570. }
  571. }
  572. return true;
  573. }
  574. companion object {
  575. private const val ID_DELETE_CONVERSATION_DIALOG = 0
  576. }
  577. }