mirror of
https://github.com/nextcloud/talk-android
synced 2025-02-03 13:12:01 +00:00
Merge pull request #1268 from nextcloud/viewBindingController
View binding controller implementation
This commit is contained in:
commit
9173bfbdaf
@ -318,7 +318,7 @@ class MainActivity : BaseActivity(), ActionBarProvider {
|
||||
} else {
|
||||
ConductorRemapping.remapChatController(
|
||||
router!!, intent.getLongExtra(BundleKeys.KEY_INTERNAL_USER_ID, -1),
|
||||
intent.getStringExtra(BundleKeys.KEY_ROOM_TOKEN), intent.extras!!, false
|
||||
intent.getStringExtra(KEY_ROOM_TOKEN)!!, intent.extras!!, false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -182,7 +182,11 @@ class MagicIncomingTextMessageViewHolder(incomingView: View) : MessageHolders
|
||||
for (key in messageParameters.keys) {
|
||||
val individualHashMap = message.messageParameters[key]
|
||||
if (individualHashMap != null) {
|
||||
if (individualHashMap["type"] == "user" || individualHashMap["type"] == "guest" || individualHashMap["type"] == "call") {
|
||||
if (
|
||||
individualHashMap["type"] == "user" ||
|
||||
individualHashMap["type"] == "guest" ||
|
||||
individualHashMap["type"] == "call"
|
||||
) {
|
||||
if (individualHashMap["id"] == message.activeUser!!.userId) {
|
||||
messageString = DisplayUtils.searchAndReplaceWithMentionSpan(
|
||||
messageText!!.context,
|
||||
|
@ -46,6 +46,7 @@ import com.nextcloud.talk.components.filebrowser.models.BrowserFile;
|
||||
import com.nextcloud.talk.components.filebrowser.models.DavResponse;
|
||||
import com.nextcloud.talk.components.filebrowser.webdav.ReadFilesystemOperation;
|
||||
import com.nextcloud.talk.jobs.DownloadFileToCacheWorker;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
||||
import com.nextcloud.talk.utils.AccountUtils;
|
||||
@ -335,7 +336,7 @@ public class MagicPreviewMessageViewHolder extends MessageHolders.IncomingImageM
|
||||
|
||||
String baseUrl = message.activeUser.getBaseUrl();
|
||||
String userId = message.activeUser.getUserId();
|
||||
String attachmentFolder = message.activeUser.getAttachmentFolder();
|
||||
String attachmentFolder = CapabilitiesUtil.getAttachmentFolder(message.activeUser);
|
||||
|
||||
String fileName = message.getSelectedIndividualHashMap().get("name");
|
||||
String mimetype = message.getSelectedIndividualHashMap().get("mimetype");
|
||||
|
@ -77,7 +77,16 @@ import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@AutoComponent(modules = [BusModule::class, ContextModule::class, DatabaseModule::class, RestModule::class, UserModule::class, ArbitraryStorageModule::class])
|
||||
@AutoComponent(
|
||||
modules = [
|
||||
BusModule::class,
|
||||
ContextModule::class,
|
||||
DatabaseModule::class,
|
||||
RestModule::class,
|
||||
UserModule::class,
|
||||
ArbitraryStorageModule::class
|
||||
]
|
||||
)
|
||||
@Singleton
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
|
@ -145,13 +145,11 @@ public abstract class BrowserController extends BaseController implements Listin
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.files_selection_done:
|
||||
onFileSelectionDone();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
if (item.getItemId() == R.id.files_selection_done) {
|
||||
onFileSelectionDone();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -64,6 +64,7 @@ import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.events.CallNotificationClick;
|
||||
import com.nextcloud.talk.events.ConfigurationChangeEvent;
|
||||
import com.nextcloud.talk.models.RingtoneSettings;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation;
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall;
|
||||
@ -278,7 +279,9 @@ public class CallNotificationController extends BaseController {
|
||||
runAllThings();
|
||||
|
||||
if (apiVersion >= 3) {
|
||||
boolean hasCallFlags = userBeingCalled.hasSpreedFeatureCapability("conversation-call-flags");
|
||||
boolean hasCallFlags =
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(userBeingCalled,
|
||||
"conversation-call-flags");
|
||||
if (hasCallFlags) {
|
||||
if (isInCallWithVideo(currentConversation.callFlag)) {
|
||||
incomingCallVoiceOrVideoTextView.setText(String.format(getResources().getString(R.string.nc_call_video),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -56,6 +56,7 @@ import com.nextcloud.talk.controllers.bottomsheet.OperationsMenuController;
|
||||
import com.nextcloud.talk.events.BottomSheetLockEvent;
|
||||
import com.nextcloud.talk.jobs.AddParticipantsToConversation;
|
||||
import com.nextcloud.talk.models.RetrofitBucket;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteOverall;
|
||||
import com.nextcloud.talk.models.json.autocomplete.AutocompleteUser;
|
||||
@ -435,20 +436,18 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
getRouter().popCurrentController();
|
||||
return true;
|
||||
case R.id.contacts_selection_done:
|
||||
selectionDone();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == android.R.id.home) {
|
||||
return getRouter().popCurrentController();
|
||||
} else if (itemId == R.id.contacts_selection_done) {
|
||||
selectionDone();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, @NonNull MenuInflater inflater) {
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
inflater.inflate(R.menu.menu_contacts, menu);
|
||||
searchItem = menu.findItem(R.id.action_search);
|
||||
@ -493,13 +492,13 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
||||
if (!isAddingParticipantsView) {
|
||||
// groups
|
||||
shareTypesList.add("1");
|
||||
} else if (currentUser.hasSpreedFeatureCapability("invite-groups-and-mails")) {
|
||||
} else if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails")) {
|
||||
// groups
|
||||
shareTypesList.add("1");
|
||||
// emails
|
||||
shareTypesList.add("4");
|
||||
}
|
||||
if (currentUser.hasSpreedFeatureCapability("circles-support")) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "circles-support")) {
|
||||
// circles
|
||||
shareTypesList.add("7");
|
||||
}
|
||||
@ -974,8 +973,8 @@ public class ContactsController extends BaseController implements SearchView.OnQ
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUser.hasSpreedFeatureCapability("last-room-activity")
|
||||
&& !currentUser.hasSpreedFeatureCapability("invite-groups-and-mails") &&
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")
|
||||
&& !CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails") &&
|
||||
"groups".equals(((UserItem) adapter.getItem(position)).getModel().getSource()) &&
|
||||
participant.isSelected() &&
|
||||
adapter.getSelectedItemCount() > 1) {
|
||||
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -21,26 +23,19 @@
|
||||
package com.nextcloud.talk.controllers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Bundle
|
||||
import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ProgressBar
|
||||
import androidx.appcompat.widget.SwitchCompat
|
||||
import androidx.emoji.widget.EmojiTextView
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.work.Data
|
||||
import androidx.work.OneTimeWorkRequest
|
||||
import androidx.work.WorkManager
|
||||
import autodagger.AutoInjector
|
||||
import butterknife.BindView
|
||||
import butterknife.OnClick
|
||||
import com.afollestad.materialdialogs.LayoutMode.WRAP_CONTENT
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import com.afollestad.materialdialogs.bottomsheets.BottomSheet
|
||||
@ -48,17 +43,19 @@ import com.afollestad.materialdialogs.datetime.dateTimePicker
|
||||
import com.bluelinelabs.conductor.RouterTransaction
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
|
||||
import com.facebook.drawee.backends.pipeline.Fresco
|
||||
import com.facebook.drawee.view.SimpleDraweeView
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.adapters.items.UserItem
|
||||
import com.nextcloud.talk.api.NcApi
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.controllers.base.BaseController
|
||||
import com.nextcloud.talk.controllers.base.NewBaseController
|
||||
import com.nextcloud.talk.controllers.bottomsheet.items.BasicListItemWithImage
|
||||
import com.nextcloud.talk.controllers.bottomsheet.items.listItemsWithImage
|
||||
import com.nextcloud.talk.controllers.util.viewBinding
|
||||
import com.nextcloud.talk.databinding.ControllerConversationInfoBinding
|
||||
import com.nextcloud.talk.events.EventStatus
|
||||
import com.nextcloud.talk.jobs.DeleteConversationWorker
|
||||
import com.nextcloud.talk.jobs.LeaveConversationWorker
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil
|
||||
import com.nextcloud.talk.models.database.UserEntity
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
||||
import com.nextcloud.talk.models.json.conversations.RoomOverall
|
||||
@ -75,11 +72,6 @@ import com.nextcloud.talk.utils.bundle.BundleKeys
|
||||
import com.nextcloud.talk.utils.preferences.preferencestorage.DatabaseStorageModule
|
||||
import com.yarolegovich.lovelydialog.LovelySaveStateHandler
|
||||
import com.yarolegovich.lovelydialog.LovelyStandardDialog
|
||||
import com.yarolegovich.mp.MaterialChoicePreference
|
||||
import com.yarolegovich.mp.MaterialPreferenceCategory
|
||||
import com.yarolegovich.mp.MaterialPreferenceScreen
|
||||
import com.yarolegovich.mp.MaterialStandardPreference
|
||||
import com.yarolegovich.mp.MaterialSwitchPreference
|
||||
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||
import eu.davidea.flexibleadapter.common.SmoothScrollLinearLayoutManager
|
||||
import io.reactivex.Observer
|
||||
@ -96,70 +88,22 @@ import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleAdapter.OnItemClickListener {
|
||||
class ConversationInfoController(args: Bundle) :
|
||||
NewBaseController(
|
||||
R.layout.controller_conversation_info,
|
||||
args
|
||||
),
|
||||
FlexibleAdapter
|
||||
.OnItemClickListener {
|
||||
private val binding: ControllerConversationInfoBinding by viewBinding(ControllerConversationInfoBinding::bind)
|
||||
|
||||
@BindView(R.id.notification_settings)
|
||||
lateinit var notificationsPreferenceScreen: MaterialPreferenceScreen
|
||||
@Inject
|
||||
@JvmField
|
||||
var ncApi: NcApi? = null
|
||||
|
||||
@BindView(R.id.progressBar)
|
||||
lateinit var progressBar: ProgressBar
|
||||
|
||||
@BindView(R.id.conversation_info_message_notifications)
|
||||
lateinit var messageNotificationLevel: MaterialChoicePreference
|
||||
|
||||
@BindView(R.id.webinar_settings)
|
||||
lateinit var conversationInfoWebinar: MaterialPreferenceScreen
|
||||
|
||||
@BindView(R.id.conversation_info_lobby)
|
||||
lateinit var conversationInfoLobby: MaterialSwitchPreference
|
||||
|
||||
@BindView(R.id.conversation_info_name)
|
||||
lateinit var nameCategoryView: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.start_time_preferences)
|
||||
lateinit var startTimeView: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.avatar_image)
|
||||
lateinit var conversationAvatarImageView: SimpleDraweeView
|
||||
|
||||
@BindView(R.id.display_name_text)
|
||||
lateinit var conversationDisplayName: EmojiTextView
|
||||
|
||||
@BindView(R.id.conversation_description)
|
||||
lateinit var descriptionCategoryView: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.description_text)
|
||||
lateinit var conversationDescription: EmojiTextView
|
||||
|
||||
@BindView(R.id.participants_list_category)
|
||||
lateinit var participantsListCategory: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.addParticipantsAction)
|
||||
lateinit var addParticipantsAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.recycler_view)
|
||||
lateinit var recyclerView: RecyclerView
|
||||
|
||||
@BindView(R.id.deleteConversationAction)
|
||||
lateinit var deleteConversationAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.leaveConversationAction)
|
||||
lateinit var leaveConversationAction: MaterialStandardPreference
|
||||
|
||||
@BindView(R.id.ownOptions)
|
||||
lateinit var ownOptionsCategory: MaterialPreferenceCategory
|
||||
|
||||
@BindView(R.id.muteCalls)
|
||||
lateinit var muteCalls: MaterialSwitchPreference
|
||||
|
||||
@set:Inject
|
||||
lateinit var ncApi: NcApi
|
||||
|
||||
@set:Inject
|
||||
lateinit var context: Context
|
||||
|
||||
@set:Inject
|
||||
lateinit var eventBus: EventBus
|
||||
@Inject
|
||||
@JvmField
|
||||
var eventBus: EventBus? = null
|
||||
|
||||
private val conversationToken: String?
|
||||
private val conversationUser: UserEntity?
|
||||
@ -207,20 +151,20 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
override fun inflateView(inflater: LayoutInflater, container: ViewGroup): View {
|
||||
return inflater.inflate(R.layout.controller_conversation_info, container, false)
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
eventBus.register(this)
|
||||
eventBus?.register(this)
|
||||
|
||||
if (databaseStorageModule == null) {
|
||||
databaseStorageModule = DatabaseStorageModule(conversationUser!!, conversationToken)
|
||||
}
|
||||
|
||||
notificationsPreferenceScreen.setStorageModule(databaseStorageModule)
|
||||
conversationInfoWebinar.setStorageModule(databaseStorageModule)
|
||||
binding.notificationSettingsView.notificationSettings.setStorageModule(databaseStorageModule)
|
||||
binding.webinarInfoView.webinarSettings.setStorageModule(databaseStorageModule)
|
||||
|
||||
binding.deleteConversationAction.setOnClickListener { showDeleteConversationDialog(null) }
|
||||
binding.leaveConversationAction.setOnClickListener { leaveConversation() }
|
||||
binding.addParticipantsAction.setOnClickListener { addParticipants() }
|
||||
|
||||
fetchRoomInfo()
|
||||
}
|
||||
@ -232,27 +176,24 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
saveStateHandler = LovelySaveStateHandler()
|
||||
}
|
||||
|
||||
addParticipantsAction.visibility = View.GONE
|
||||
binding.addParticipantsAction.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun setupWebinaryView() {
|
||||
if (conversationUser!!.hasSpreedFeatureCapability("webinary-lobby") &&
|
||||
(
|
||||
conversation!!.type == Conversation.ConversationType.ROOM_GROUP_CALL ||
|
||||
conversation!!.type == Conversation.ConversationType.ROOM_PUBLIC_CALL
|
||||
) &&
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "webinary-lobby") &&
|
||||
webinaryRoomType(conversation!!) &&
|
||||
conversation!!.canModerate(conversationUser)
|
||||
) {
|
||||
conversationInfoWebinar.visibility = View.VISIBLE
|
||||
binding.webinarInfoView.webinarSettings.visibility = View.VISIBLE
|
||||
|
||||
val isLobbyOpenToModeratorsOnly =
|
||||
conversation!!.lobbyState == Conversation.LobbyState.LOBBY_STATE_MODERATORS_ONLY
|
||||
(conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
.isChecked = isLobbyOpenToModeratorsOnly
|
||||
|
||||
reconfigureLobbyTimerView()
|
||||
|
||||
startTimeView.setOnClickListener {
|
||||
binding.webinarInfoView.startTimePreferences.setOnClickListener {
|
||||
MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
|
||||
val currentTimeCalendar = Calendar.getInstance()
|
||||
if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != 0L) {
|
||||
@ -273,17 +214,25 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
(conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat).setOnCheckedChangeListener { _, _ ->
|
||||
reconfigureLobbyTimerView()
|
||||
submitLobbyChanges()
|
||||
}
|
||||
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
.setOnCheckedChangeListener { _, _ ->
|
||||
reconfigureLobbyTimerView()
|
||||
submitLobbyChanges()
|
||||
}
|
||||
} else {
|
||||
conversationInfoWebinar.visibility = View.GONE
|
||||
binding.webinarInfoView.webinarSettings.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
private fun webinaryRoomType(conversation: Conversation): Boolean {
|
||||
return conversation.type == Conversation.ConversationType.ROOM_GROUP_CALL ||
|
||||
conversation.type == Conversation.ConversationType.ROOM_PUBLIC_CALL
|
||||
}
|
||||
|
||||
fun reconfigureLobbyTimerView(dateTime: Calendar? = null) {
|
||||
val isChecked = (conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat).isChecked
|
||||
val isChecked =
|
||||
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
.isChecked
|
||||
|
||||
if (dateTime != null && isChecked) {
|
||||
conversation!!.lobbyTimer = (dateTime.timeInMillis - (dateTime.time.seconds * 1000)) / 1000
|
||||
@ -294,35 +243,44 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
conversation!!.lobbyState = if (isChecked) Conversation.LobbyState
|
||||
.LOBBY_STATE_MODERATORS_ONLY else Conversation.LobbyState.LOBBY_STATE_ALL_PARTICIPANTS
|
||||
|
||||
if (conversation!!.lobbyTimer != null && conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE && conversation!!.lobbyTimer != 0L) {
|
||||
startTimeView.setSummary(DateUtils.getLocalDateStringFromTimestampForLobby(conversation!!.lobbyTimer))
|
||||
if (
|
||||
conversation!!.lobbyTimer != null &&
|
||||
conversation!!.lobbyTimer != java.lang.Long.MIN_VALUE &&
|
||||
conversation!!.lobbyTimer != 0L
|
||||
) {
|
||||
binding.webinarInfoView.startTimePreferences.setSummary(
|
||||
DateUtils.getLocalDateStringFromTimestampForLobby(
|
||||
conversation!!.lobbyTimer
|
||||
)
|
||||
)
|
||||
} else {
|
||||
startTimeView.setSummary(R.string.nc_manual)
|
||||
binding.webinarInfoView.startTimePreferences.setSummary(R.string.nc_manual)
|
||||
}
|
||||
|
||||
if (isChecked) {
|
||||
startTimeView.visibility = View.VISIBLE
|
||||
binding.webinarInfoView.startTimePreferences.visibility = View.VISIBLE
|
||||
} else {
|
||||
startTimeView.visibility = View.GONE
|
||||
binding.webinarInfoView.startTimePreferences.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
fun submitLobbyChanges() {
|
||||
val state = if (
|
||||
(conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat).isChecked
|
||||
(binding.webinarInfoView.conversationInfoLobby.findViewById<View>(R.id.mp_checkable) as SwitchCompat)
|
||||
.isChecked
|
||||
) 1 else 0
|
||||
|
||||
val apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
|
||||
|
||||
ncApi.setLobbyForConversation(
|
||||
ncApi?.setLobbyForConversation(
|
||||
ApiUtils.getCredentials(conversationUser!!.username, conversationUser.token),
|
||||
ApiUtils.getUrlForRoomWebinaryLobby(apiVersion, conversationUser.baseUrl, conversation!!.token),
|
||||
state,
|
||||
conversation!!.lobbyTimer
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onComplete() {
|
||||
}
|
||||
|
||||
@ -352,7 +310,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
override fun onDetach(view: View) {
|
||||
super.onDetach(view)
|
||||
eventBus.unregister(this)
|
||||
eventBus?.unregister(this)
|
||||
}
|
||||
|
||||
private fun showDeleteConversationDialog(savedInstanceState: Bundle?) {
|
||||
@ -397,9 +355,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
val layoutManager = SmoothScrollLinearLayoutManager(activity)
|
||||
recyclerView.layoutManager = layoutManager
|
||||
recyclerView.setHasFixedSize(true)
|
||||
recyclerView.adapter = adapter
|
||||
binding.recyclerView.layoutManager = layoutManager
|
||||
binding.recyclerView.setHasFixedSize(true)
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
adapter!!.addListener(this)
|
||||
}
|
||||
@ -438,17 +396,17 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
setupAdapter()
|
||||
|
||||
participantsListCategory.visibility = View.VISIBLE
|
||||
binding.participantsListCategory.visibility = View.VISIBLE
|
||||
adapter!!.updateDataSet(recyclerViewItems)
|
||||
}
|
||||
|
||||
override fun getTitle(): String? {
|
||||
return if (hasAvatarSpacing) {
|
||||
" " + resources!!.getString(R.string.nc_conversation_menu_conversation_info)
|
||||
} else {
|
||||
resources!!.getString(R.string.nc_conversation_menu_conversation_info)
|
||||
}
|
||||
}
|
||||
override val title: String
|
||||
get() =
|
||||
if (hasAvatarSpacing) {
|
||||
" " + resources!!.getString(R.string.nc_conversation_menu_conversation_info)
|
||||
} else {
|
||||
resources!!.getString(R.string.nc_conversation_menu_conversation_info)
|
||||
}
|
||||
|
||||
private fun getListOfParticipants() {
|
||||
var apiVersion = 1
|
||||
@ -457,13 +415,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
|
||||
}
|
||||
|
||||
ncApi.getPeersForCall(
|
||||
ncApi?.getPeersForCall(
|
||||
credentials,
|
||||
ApiUtils.getUrlForParticipants(apiVersion, conversationUser!!.baseUrl, conversationToken)
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<ParticipantsOverall> {
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<ParticipantsOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
participantsDisposable = d
|
||||
}
|
||||
@ -481,7 +439,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
})
|
||||
}
|
||||
|
||||
@OnClick(R.id.addParticipantsAction)
|
||||
internal fun addParticipants() {
|
||||
val bundle = Bundle()
|
||||
val existingParticipantsId = arrayListOf<String>()
|
||||
@ -511,8 +468,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
)
|
||||
}
|
||||
|
||||
@OnClick(R.id.leaveConversationAction)
|
||||
internal fun leaveConversation() {
|
||||
private fun leaveConversation() {
|
||||
workerData?.let {
|
||||
WorkManager.getInstance().enqueue(
|
||||
OneTimeWorkRequest.Builder(
|
||||
@ -535,11 +491,6 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
}
|
||||
|
||||
@OnClick(R.id.deleteConversationAction)
|
||||
internal fun deleteConversationClick() {
|
||||
showDeleteConversationDialog(null)
|
||||
}
|
||||
|
||||
private fun popTwoLastControllers() {
|
||||
var backstack = router.backstack
|
||||
backstack = backstack.subList(0, backstack.size - 2)
|
||||
@ -553,10 +504,10 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
apiVersion = ApiUtils.getConversationApiVersion(conversationUser, intArrayOf(ApiUtils.APIv4, 1))
|
||||
}
|
||||
|
||||
ncApi.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, conversationUser!!.baseUrl, conversationToken))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<RoomOverall> {
|
||||
ncApi?.getRoom(credentials, ApiUtils.getUrlForRoom(apiVersion, conversationUser!!.baseUrl, conversationToken))
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<RoomOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
roomDisposable = d
|
||||
}
|
||||
@ -567,49 +518,49 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
val conversationCopy = conversation
|
||||
|
||||
if (conversationCopy!!.canModerate(conversationUser)) {
|
||||
addParticipantsAction.visibility = View.VISIBLE
|
||||
binding.addParticipantsAction.visibility = View.VISIBLE
|
||||
} else {
|
||||
addParticipantsAction.visibility = View.GONE
|
||||
binding.addParticipantsAction.visibility = View.GONE
|
||||
}
|
||||
|
||||
if (isAttached && (!isBeingDestroyed || !isDestroyed)) {
|
||||
ownOptionsCategory.visibility = View.VISIBLE
|
||||
binding.ownOptions.visibility = View.VISIBLE
|
||||
|
||||
setupWebinaryView()
|
||||
|
||||
if (!conversation!!.canLeave(conversationUser)) {
|
||||
leaveConversationAction.visibility = View.GONE
|
||||
binding.leaveConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
leaveConversationAction.visibility = View.VISIBLE
|
||||
binding.leaveConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (!conversation!!.canDelete(conversationUser)) {
|
||||
deleteConversationAction.visibility = View.GONE
|
||||
binding.deleteConversationAction.visibility = View.GONE
|
||||
} else {
|
||||
deleteConversationAction.visibility = View.VISIBLE
|
||||
binding.deleteConversationAction.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
if (Conversation.ConversationType.ROOM_SYSTEM == conversation!!.type) {
|
||||
muteCalls.visibility = View.GONE
|
||||
binding.notificationSettingsView.muteCalls.visibility = View.GONE
|
||||
}
|
||||
|
||||
getListOfParticipants()
|
||||
|
||||
progressBar.visibility = View.GONE
|
||||
binding.progressBar.visibility = View.GONE
|
||||
|
||||
nameCategoryView.visibility = View.VISIBLE
|
||||
binding.conversationInfoName.visibility = View.VISIBLE
|
||||
|
||||
conversationDisplayName.text = conversation!!.displayName
|
||||
binding.displayNameText.text = conversation!!.displayName
|
||||
|
||||
if (conversation!!.description != null && !conversation!!.description.isEmpty()) {
|
||||
conversationDescription.text = conversation!!.description
|
||||
descriptionCategoryView.visibility = View.VISIBLE
|
||||
binding.descriptionText.text = conversation!!.description
|
||||
binding.conversationDescription.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
loadConversationAvatar()
|
||||
adjustNotificationLevelUI()
|
||||
|
||||
notificationsPreferenceScreen.visibility = View.VISIBLE
|
||||
binding.notificationSettingsView.notificationSettings.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
@ -624,9 +575,12 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
|
||||
private fun adjustNotificationLevelUI() {
|
||||
if (conversation != null) {
|
||||
if (conversationUser != null && conversationUser.hasSpreedFeatureCapability("notification-levels")) {
|
||||
messageNotificationLevel.isEnabled = true
|
||||
messageNotificationLevel.alpha = 1.0f
|
||||
if (
|
||||
conversationUser != null &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "notification-levels")
|
||||
) {
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.isEnabled = true
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.alpha = 1.0f
|
||||
|
||||
if (conversation!!.notificationLevel != Conversation.NotificationLevel.DEFAULT) {
|
||||
val stringValue: String =
|
||||
@ -637,13 +591,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
else -> "mention"
|
||||
}
|
||||
|
||||
messageNotificationLevel.value = stringValue
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.value = stringValue
|
||||
} else {
|
||||
setProperNotificationValue(conversation)
|
||||
}
|
||||
} else {
|
||||
messageNotificationLevel.isEnabled = false
|
||||
messageNotificationLevel.alpha = 0.38f
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.isEnabled = false
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.alpha = LOW_EMPHASIS_OPACITY
|
||||
setProperNotificationValue(conversation)
|
||||
}
|
||||
}
|
||||
@ -652,13 +606,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
private fun setProperNotificationValue(conversation: Conversation?) {
|
||||
if (conversation!!.type == Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) {
|
||||
// hack to see if we get mentioned always or just on mention
|
||||
if (conversationUser!!.hasSpreedFeatureCapability("mention-flag")) {
|
||||
messageNotificationLevel.value = "always"
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "mention-flag")) {
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "always"
|
||||
} else {
|
||||
messageNotificationLevel.value = "mention"
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "mention"
|
||||
}
|
||||
} else {
|
||||
messageNotificationLevel.value = "mention"
|
||||
binding.notificationSettingsView.conversationInfoMessageNotifications.value = "mention"
|
||||
}
|
||||
}
|
||||
|
||||
@ -666,7 +620,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
when (conversation!!.type) {
|
||||
Conversation.ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL -> if (!TextUtils.isEmpty(conversation!!.name)) {
|
||||
val draweeController = Fresco.newDraweeControllerBuilder()
|
||||
.setOldController(conversationAvatarImageView.controller)
|
||||
.setOldController(binding.avatarImage.controller)
|
||||
.setAutoPlayAnimations(true)
|
||||
.setImageRequest(
|
||||
DisplayUtils.getImageRequestForUrl(
|
||||
@ -678,20 +632,20 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
)
|
||||
)
|
||||
.build()
|
||||
conversationAvatarImageView.controller = draweeController
|
||||
binding.avatarImage.controller = draweeController
|
||||
}
|
||||
Conversation.ConversationType.ROOM_GROUP_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
|
||||
Conversation.ConversationType.ROOM_GROUP_CALL -> binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
R.drawable.ic_circular_group
|
||||
)
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL -> conversationAvatarImageView.hierarchy.setPlaceholderImage(
|
||||
Conversation.ConversationType.ROOM_PUBLIC_CALL -> binding.avatarImage.hierarchy.setPlaceholderImage(
|
||||
R.drawable.ic_circular_link
|
||||
)
|
||||
Conversation.ConversationType.ROOM_SYSTEM -> {
|
||||
val layers = arrayOfNulls<Drawable>(2)
|
||||
layers[0] = context.getDrawable(R.drawable.ic_launcher_background)
|
||||
layers[1] = context.getDrawable(R.drawable.ic_launcher_foreground)
|
||||
layers[0] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_background)
|
||||
layers[1] = ContextCompat.getDrawable(context!!, R.drawable.ic_launcher_foreground)
|
||||
val layerDrawable = LayerDrawable(layers)
|
||||
conversationAvatarImageView.hierarchy.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
binding.avatarImage.hierarchy.setPlaceholderImage(DisplayUtils.getRoundedDrawable(layerDrawable))
|
||||
}
|
||||
|
||||
else -> {
|
||||
@ -720,7 +674,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
if (participant.type == Participant.ParticipantType.MODERATOR ||
|
||||
participant.type == Participant.ParticipantType.GUEST_MODERATOR
|
||||
) {
|
||||
ncApi.demoteAttendeeFromModerator(
|
||||
ncApi?.demoteAttendeeFromModerator(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRoomModerators(
|
||||
apiVersion,
|
||||
@ -729,13 +683,13 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.attendeeId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(subscriber)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(subscriber)
|
||||
} else if (participant.type == Participant.ParticipantType.USER ||
|
||||
participant.type == Participant.ParticipantType.GUEST
|
||||
) {
|
||||
ncApi.promoteAttendeeToModerator(
|
||||
ncApi?.promoteAttendeeToModerator(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRoomModerators(
|
||||
apiVersion,
|
||||
@ -744,9 +698,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.attendeeId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(subscriber)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
@ -769,7 +723,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
if (participant.type == Participant.ParticipantType.MODERATOR) {
|
||||
ncApi.demoteModeratorToUser(
|
||||
ncApi?.demoteModeratorToUser(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRoomModerators(
|
||||
apiVersion,
|
||||
@ -778,11 +732,11 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(subscriber)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(subscriber)
|
||||
} else if (participant.type == Participant.ParticipantType.USER) {
|
||||
ncApi.promoteUserToModerator(
|
||||
ncApi?.promoteUserToModerator(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRoomModerators(
|
||||
apiVersion,
|
||||
@ -791,15 +745,15 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(subscriber)
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(subscriber)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeAttendeeFromConversation(apiVersion: Int, participant: Participant) {
|
||||
if (apiVersion >= ApiUtils.APIv4) {
|
||||
ncApi.removeAttendeeFromConversation(
|
||||
ncApi?.removeAttendeeFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForAttendees(
|
||||
apiVersion,
|
||||
@ -808,9 +762,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.attendeeId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
@ -830,7 +784,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
if (participant.type == Participant.ParticipantType.GUEST ||
|
||||
participant.type == Participant.ParticipantType.USER_FOLLOWING_LINK
|
||||
) {
|
||||
ncApi.removeParticipantFromConversation(
|
||||
ncApi?.removeParticipantFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRemovingParticipantFromConversation(
|
||||
conversationUser!!.baseUrl,
|
||||
@ -839,9 +793,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.sessionId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
@ -858,7 +812,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
})
|
||||
} else {
|
||||
ncApi.removeParticipantFromConversation(
|
||||
ncApi?.removeParticipantFromConversation(
|
||||
credentials,
|
||||
ApiUtils.getUrlForRemovingParticipantFromConversation(
|
||||
conversationUser!!.baseUrl,
|
||||
@ -867,9 +821,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
),
|
||||
participant.userId
|
||||
)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(object : Observer<GenericOverall> {
|
||||
?.subscribeOn(Schedulers.io())
|
||||
?.observeOn(AndroidSchedulers.mainThread())
|
||||
?.subscribe(object : Observer<GenericOverall> {
|
||||
override fun onSubscribe(d: Disposable) {
|
||||
}
|
||||
|
||||
@ -904,7 +858,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
val items = mutableListOf(
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_lock_grey600_24px,
|
||||
context.getString(R.string.nc_attendee_pin, participant.attendeePin)
|
||||
context!!.getString(R.string.nc_attendee_pin, participant.attendeePin)
|
||||
)
|
||||
)
|
||||
MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
|
||||
@ -930,7 +884,7 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
val items = mutableListOf(
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_delete_grey600_24dp,
|
||||
context.getString(R.string.nc_remove_group_and_members)
|
||||
context!!.getString(R.string.nc_remove_group_and_members)
|
||||
)
|
||||
)
|
||||
MaterialDialog(activity!!, BottomSheet(WRAP_CONTENT)).show {
|
||||
@ -946,16 +900,16 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
return true
|
||||
}
|
||||
|
||||
var items = mutableListOf(
|
||||
val items = mutableListOf(
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_lock_grey600_24px,
|
||||
context.getString(R.string.nc_attendee_pin, participant.attendeePin)
|
||||
context!!.getString(R.string.nc_attendee_pin, participant.attendeePin)
|
||||
),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_promote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context.getString(R.string.nc_demote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context!!.getString(R.string.nc_promote)),
|
||||
BasicListItemWithImage(R.drawable.ic_pencil_grey600_24dp, context!!.getString(R.string.nc_demote)),
|
||||
BasicListItemWithImage(
|
||||
R.drawable.ic_delete_grey600_24dp,
|
||||
context.getString(R.string.nc_remove_participant)
|
||||
context!!.getString(R.string.nc_remove_participant)
|
||||
)
|
||||
)
|
||||
|
||||
@ -1011,9 +965,9 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "ConversationInfoController"
|
||||
private const val ID_DELETE_CONVERSATION_DIALOG = 0
|
||||
private val LOW_EMPHASIS_OPACITY: Float = 0.38f
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1025,7 +979,11 @@ class ConversationInfoController(args: Bundle) : BaseController(args), FlexibleA
|
||||
val rightIsGroup = right.model.actorType == GROUPS
|
||||
if (leftIsGroup != rightIsGroup) {
|
||||
// Groups below participants
|
||||
return if (rightIsGroup) { -1 } else { 1 }
|
||||
return if (rightIsGroup) {
|
||||
-1
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}
|
||||
|
||||
if (left.isOnline && !right.isOnline) {
|
||||
|
@ -79,6 +79,7 @@ import com.nextcloud.talk.jobs.AccountRemovalWorker;
|
||||
import com.nextcloud.talk.jobs.ContactAddressBookWorker;
|
||||
import com.nextcloud.talk.jobs.DeleteConversationWorker;
|
||||
import com.nextcloud.talk.jobs.UploadAndShareFilesWorker;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation;
|
||||
import com.nextcloud.talk.models.json.participants.Participant;
|
||||
@ -280,13 +281,14 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
currentUser = userUtils.getCurrentUser();
|
||||
|
||||
if (currentUser != null) {
|
||||
if (currentUser.isServerEOL()) {
|
||||
if (CapabilitiesUtil.isServerEOL(currentUser)) {
|
||||
showServerEOLDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
credentials = ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken());
|
||||
shouldUseLastMessageLayout = currentUser.hasSpreedFeatureCapability("last-room-activity");
|
||||
shouldUseLastMessageLayout = CapabilitiesUtil.hasSpreedFeatureCapability(currentUser,
|
||||
"last-room-activity");
|
||||
if (getActivity() != null && getActivity() instanceof MainActivity) {
|
||||
loadUserAvatar(((MainActivity) getActivity()).binding.switchAccountButton);
|
||||
}
|
||||
@ -489,7 +491,7 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUser.hasSpreedFeatureCapability("last-room-activity")) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")) {
|
||||
Collections.sort(callItems, (o1, o2) -> {
|
||||
Conversation conversation1 = ((ConversationItem) o1).getModel();
|
||||
Conversation conversation2 = ((ConversationItem) o2).getModel();
|
||||
@ -817,7 +819,7 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
if (showShareToScreen) {
|
||||
Log.d(TAG, "sharing to multiple rooms not yet implemented. onItemLongClick is ignored.");
|
||||
|
||||
} else if (currentUser.hasSpreedFeatureCapability("last-room-activity")) {
|
||||
} else if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "last-room-activity")) {
|
||||
Object clickedItem = adapter.getItem(position);
|
||||
if (clickedItem != null) {
|
||||
Conversation conversation;
|
||||
@ -883,7 +885,9 @@ public class ConversationsListController extends BaseController implements Searc
|
||||
|
||||
Data data = new Data.Builder()
|
||||
.putStringArray(UploadAndShareFilesWorker.DEVICE_SOURCEFILES, filesToShareArray)
|
||||
.putString(UploadAndShareFilesWorker.NC_TARGETPATH, currentUser.getAttachmentFolder())
|
||||
.putString(
|
||||
UploadAndShareFilesWorker.NC_TARGETPATH,
|
||||
CapabilitiesUtil.getAttachmentFolder(currentUser))
|
||||
.putString(UploadAndShareFilesWorker.ROOM_TOKEN, selectedConversation.getToken())
|
||||
.build();
|
||||
OneTimeWorkRequest uploadWorker = new OneTimeWorkRequest.Builder(UploadAndShareFilesWorker.class)
|
||||
|
@ -1,183 +0,0 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.nextcloud.talk.controllers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.KeyguardManager;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
import com.nextcloud.talk.utils.SecurityUtils;
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import autodagger.AutoInjector;
|
||||
import butterknife.OnClick;
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication.class)
|
||||
public class LockedController extends BaseController {
|
||||
public static final String TAG = "LockedController";
|
||||
private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112;
|
||||
|
||||
@Inject
|
||||
AppPreferences appPreferences;
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_locked, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onViewBound(@NonNull View view) {
|
||||
super.onViewBound(view);
|
||||
NextcloudTalkApplication.Companion.getSharedApplication().getComponentApplication().inject(this);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@Override
|
||||
protected void onAttach(@NonNull View view) {
|
||||
super.onAttach(view);
|
||||
if (getActivity() != null && getResources() != null) {
|
||||
DisplayUtils.applyColorToStatusBar(getActivity(), ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null));
|
||||
DisplayUtils.applyColorToNavigationBar(getActivity().getWindow(), ResourcesCompat.getColor(getResources(), R.color.colorPrimary, null));
|
||||
}
|
||||
checkIfWeAreSecure();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
@OnClick(R.id.unlockContainer)
|
||||
void unlock() {
|
||||
checkIfWeAreSecure();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void showBiometricDialog() {
|
||||
Context context = getActivity();
|
||||
|
||||
if (context != null) {
|
||||
final BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(String.format(context.getString(R.string.nc_biometric_unlock), context.getString(R.string.nc_app_name)))
|
||||
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
||||
.build();
|
||||
|
||||
Executor executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
final BiometricPrompt biometricPrompt = new BiometricPrompt((FragmentActivity) context, executor,
|
||||
new BiometricPrompt.AuthenticationCallback() {
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
Log.d(TAG, "Fingerprint recognised successfully");
|
||||
new Handler(Looper.getMainLooper()).post(() -> getRouter().popCurrentController());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
Log.d(TAG, "Fingerprint not recognised");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
|
||||
super.onAuthenticationError(errorCode, errString);
|
||||
showAuthenticationScreen();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
BiometricPrompt.CryptoObject cryptoObject = SecurityUtils.getCryptoObject();
|
||||
if (cryptoObject != null) {
|
||||
biometricPrompt.authenticate(promptInfo, cryptoObject);
|
||||
} else {
|
||||
biometricPrompt.authenticate(promptInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private void checkIfWeAreSecure() {
|
||||
if (getActivity() != null) {
|
||||
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
|
||||
if (keyguardManager != null && keyguardManager.isKeyguardSecure() && appPreferences.getIsScreenLocked()) {
|
||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
||||
showBiometricDialog();
|
||||
} else {
|
||||
getRouter().popCurrentController();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void showAuthenticationScreen() {
|
||||
if (getActivity() != null) {
|
||||
KeyguardManager keyguardManager = (KeyguardManager) getActivity().getSystemService(Context.KEYGUARD_SERVICE);
|
||||
Intent intent = keyguardManager.createConfirmDeviceCredentialIntent(null, null);
|
||||
if (intent != null) {
|
||||
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (SecurityUtils.checkIfWeAreAuthenticated(appPreferences.getScreenLockTimeout())) {
|
||||
Log.d(TAG, "All went well, dismiss locked controller");
|
||||
getRouter().popCurrentController();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Authorization failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AppBarLayoutType getAppBarLayoutType() {
|
||||
return AppBarLayoutType.EMPTY;
|
||||
}
|
||||
}
|
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.talk.controllers
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.biometric.BiometricPrompt
|
||||
import androidx.biometric.BiometricPrompt.PromptInfo
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import autodagger.AutoInjector
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.controllers.base.NewBaseController
|
||||
import com.nextcloud.talk.controllers.util.viewBinding
|
||||
import com.nextcloud.talk.databinding.ControllerLockedBinding
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.SecurityUtils
|
||||
import java.util.concurrent.Executor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
class LockedController : NewBaseController(R.layout.controller_locked) {
|
||||
private val binding: ControllerLockedBinding by viewBinding(ControllerLockedBinding::bind)
|
||||
|
||||
override val appBarLayoutType: AppBarLayoutType
|
||||
get() = AppBarLayoutType.EMPTY
|
||||
|
||||
companion object {
|
||||
const val TAG = "LockedController"
|
||||
private const val REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 112
|
||||
}
|
||||
|
||||
override fun onViewBound(view: View) {
|
||||
super.onViewBound(view)
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
binding.unlockContainer.setOnClickListener {
|
||||
unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
override fun onAttach(view: View) {
|
||||
super.onAttach(view)
|
||||
if (activity != null && resources != null) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
|
||||
)
|
||||
DisplayUtils.applyColorToNavigationBar(
|
||||
activity!!.window,
|
||||
ResourcesCompat.getColor(resources!!, R.color.colorPrimary, null)
|
||||
)
|
||||
}
|
||||
checkIfWeAreSecure()
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
fun unlock() {
|
||||
checkIfWeAreSecure()
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private fun showBiometricDialog() {
|
||||
val context: Context? = activity
|
||||
if (context != null) {
|
||||
val promptInfo = PromptInfo.Builder()
|
||||
.setTitle(
|
||||
String.format(
|
||||
context.getString(R.string.nc_biometric_unlock),
|
||||
context.getString(R.string.nc_app_name)
|
||||
)
|
||||
)
|
||||
.setNegativeButtonText(context.getString(R.string.nc_cancel))
|
||||
.build()
|
||||
val executor: Executor = Executors.newSingleThreadExecutor()
|
||||
val biometricPrompt = BiometricPrompt(
|
||||
(context as FragmentActivity?)!!, executor,
|
||||
object : BiometricPrompt.AuthenticationCallback() {
|
||||
override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
Log.d(TAG, "Fingerprint recognised successfully")
|
||||
Handler(Looper.getMainLooper()).post { router.popCurrentController() }
|
||||
}
|
||||
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
Log.d(TAG, "Fingerprint not recognised")
|
||||
}
|
||||
|
||||
override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
|
||||
super.onAuthenticationError(errorCode, errString)
|
||||
showAuthenticationScreen()
|
||||
}
|
||||
}
|
||||
)
|
||||
val cryptoObject = SecurityUtils.getCryptoObject()
|
||||
if (cryptoObject != null) {
|
||||
biometricPrompt.authenticate(promptInfo, cryptoObject)
|
||||
} else {
|
||||
biometricPrompt.authenticate(promptInfo)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.M)
|
||||
private fun checkIfWeAreSecure() {
|
||||
val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
||||
if (keyguardManager?.isKeyguardSecure == true && appPreferences!!.isScreenLocked) {
|
||||
if (!SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)) {
|
||||
showBiometricDialog()
|
||||
} else {
|
||||
router.popCurrentController()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun showAuthenticationScreen() {
|
||||
val keyguardManager = activity?.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager?
|
||||
val intent = keyguardManager?.createConfirmDeviceCredentialIntent(null, null)
|
||||
if (intent != null) {
|
||||
startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
SecurityUtils.checkIfWeAreAuthenticated(appPreferences!!.screenLockTimeout)
|
||||
) {
|
||||
Log.d(TAG, "All went well, dismiss locked controller")
|
||||
router.popCurrentController()
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "Authorization failed")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -53,6 +53,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.components.filebrowser.controllers.BrowserController;
|
||||
import com.nextcloud.talk.components.filebrowser.controllers.BrowserForAvatarController;
|
||||
import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
||||
import com.nextcloud.talk.models.json.userprofile.Scope;
|
||||
@ -156,70 +157,67 @@ public class ProfileController extends BaseController {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.edit:
|
||||
if (edit) {
|
||||
save();
|
||||
if (item.getItemId() == R.id.edit) {
|
||||
if (edit) {
|
||||
save();
|
||||
}
|
||||
|
||||
edit = !edit;
|
||||
|
||||
if (edit) {
|
||||
item.setTitle(R.string.save);
|
||||
|
||||
getActivity().findViewById(R.id.emptyList).setVisibility(View.GONE);
|
||||
getActivity().findViewById(R.id.userinfo_list).setVisibility(View.VISIBLE);
|
||||
|
||||
if (CapabilitiesUtil.isAvatarEndpointAvailable(currentUser)) {
|
||||
// TODO later avatar can also be checked via user fields, for now it is in Talk capability
|
||||
getActivity().findViewById(R.id.avatar_buttons).setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
edit = !edit;
|
||||
ncApi.getEditableUserProfileFields(
|
||||
ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
|
||||
ApiUtils.getUrlForUserFields(currentUser.getBaseUrl()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<UserProfileFieldsOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
if (edit) {
|
||||
item.setTitle(R.string.save);
|
||||
@Override
|
||||
public void onNext(@io.reactivex.annotations.NonNull UserProfileFieldsOverall userProfileFieldsOverall) {
|
||||
editableFields = userProfileFieldsOverall.getOcs().getData();
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
getActivity().findViewById(R.id.emptyList).setVisibility(View.GONE);
|
||||
getActivity().findViewById(R.id.userinfo_list).setVisibility(View.VISIBLE);
|
||||
@Override
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
Log.e(TAG, "Error loading editable user profile from server", e);
|
||||
edit = false;
|
||||
}
|
||||
|
||||
if (currentUser.isAvatarEndpointAvailable()) {
|
||||
// TODO later avatar can also be checked via user fields, for now it is in Talk capability
|
||||
getActivity().findViewById(R.id.avatar_buttons).setVisibility(View.VISIBLE);
|
||||
}
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// unused atm
|
||||
}
|
||||
});
|
||||
} else {
|
||||
item.setTitle(R.string.edit);
|
||||
getActivity().findViewById(R.id.avatar_buttons).setVisibility(View.INVISIBLE);
|
||||
|
||||
ncApi.getEditableUserProfileFields(
|
||||
ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
|
||||
ApiUtils.getUrlForUserFields(currentUser.getBaseUrl()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<UserProfileFieldsOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
// unused atm
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(@io.reactivex.annotations.NonNull UserProfileFieldsOverall userProfileFieldsOverall) {
|
||||
editableFields = userProfileFieldsOverall.getOcs().getData();
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
Log.e(TAG, "Error loading editable user profile from server", e);
|
||||
edit = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
// unused atm
|
||||
}
|
||||
});
|
||||
} else {
|
||||
item.setTitle(R.string.edit);
|
||||
getActivity().findViewById(R.id.avatar_buttons).setVisibility(View.INVISIBLE);
|
||||
|
||||
if (adapter.filteredDisplayList.size() == 0) {
|
||||
getActivity().findViewById(R.id.emptyList).setVisibility(View.VISIBLE);
|
||||
getActivity().findViewById(R.id.userinfo_list).setVisibility(View.GONE);
|
||||
}
|
||||
if (adapter.filteredDisplayList.size() == 0) {
|
||||
getActivity().findViewById(R.id.emptyList).setVisibility(View.VISIBLE);
|
||||
getActivity().findViewById(R.id.userinfo_list).setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
adapter.notifyDataSetChanged();
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -345,7 +343,7 @@ public class ProfileController extends BaseController {
|
||||
}
|
||||
|
||||
// show edit button
|
||||
if (currentUser.canEditScopes()) {
|
||||
if (CapabilitiesUtil.canEditScopes(currentUser)) {
|
||||
ncApi.getEditableUserProfileFields(ApiUtils.getCredentials(currentUser.getUsername(), currentUser.getToken()),
|
||||
ApiUtils.getUrlForUserFields(currentUser.getBaseUrl()))
|
||||
.subscribeOn(Schedulers.io())
|
||||
|
@ -116,12 +116,10 @@ public class RingtoneSelectionController extends BaseController implements Flexi
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
return getRouter().popCurrentController();
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
return getRouter().popCurrentController();
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void prepareViews() {
|
||||
|
@ -68,6 +68,7 @@ import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.jobs.AccountRemovalWorker;
|
||||
import com.nextcloud.talk.jobs.ContactAddressBookWorker;
|
||||
import com.nextcloud.talk.models.RingtoneSettings;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
||||
import com.nextcloud.talk.models.json.userprofile.UserProfileOverall;
|
||||
@ -317,7 +318,7 @@ public class SettingsController extends BaseController {
|
||||
.popChangeHandler(new HorizontalChangeHandler()));
|
||||
});
|
||||
|
||||
if (userUtils.getCurrentUser().isPhoneBookIntegrationAvailable()) {
|
||||
if (CapabilitiesUtil.isPhoneBookIntegrationAvailable(userUtils.getCurrentUser())) {
|
||||
phoneBookIntegrationPreference.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
phoneBookIntegrationPreference.setVisibility(View.GONE);
|
||||
@ -456,8 +457,8 @@ public class SettingsController extends BaseController {
|
||||
((Checkable) incognitoKeyboardSwitchPreference.findViewById(R.id.mp_checkable)).setChecked(appPreferences.getIsKeyboardIncognito());
|
||||
}
|
||||
|
||||
if (userUtils.getCurrentUser().isReadStatusAvailable()) {
|
||||
((Checkable) readPrivacyPreference.findViewById(R.id.mp_checkable)).setChecked(!currentUser.isReadStatusPrivate());
|
||||
if (CapabilitiesUtil.isReadStatusAvailable(userUtils.getCurrentUser())) {
|
||||
((Checkable) readPrivacyPreference.findViewById(R.id.mp_checkable)).setChecked(!CapabilitiesUtil.isReadStatusPrivate(currentUser));
|
||||
} else {
|
||||
readPrivacyPreference.setVisibility(View.GONE);
|
||||
}
|
||||
@ -537,12 +538,12 @@ public class SettingsController extends BaseController {
|
||||
|
||||
baseUrlTextView.setText(Uri.parse(currentUser.getBaseUrl()).getHost());
|
||||
|
||||
if (currentUser.isServerEOL()) {
|
||||
if (CapabilitiesUtil.isServerEOL(currentUser)) {
|
||||
serverAgeTextView.setTextColor(ContextCompat.getColor(context, R.color.nc_darkRed));
|
||||
serverAgeTextView.setText(R.string.nc_settings_server_eol);
|
||||
serverAgeIcon.setColorFilter(ContextCompat.getColor(context, R.color.nc_darkRed),
|
||||
PorterDuff.Mode.SRC_IN);
|
||||
} else if (currentUser.isServerAlmostEOL()) {
|
||||
} else if (CapabilitiesUtil.isServerAlmostEOL(currentUser)) {
|
||||
serverAgeTextView.setTextColor(ContextCompat.getColor(context, R.color.nc_darkYellow));
|
||||
serverAgeTextView.setText(R.string.nc_settings_server_almost_eol);
|
||||
serverAgeIcon.setColorFilter(ContextCompat.getColor(context, R.color.nc_darkYellow),
|
||||
|
@ -84,13 +84,11 @@ public abstract class BaseController extends ButterKnifeController {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
getRouter().popCurrentController();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
if (item.getItemId() == android.R.id.home) {
|
||||
getRouter().popCurrentController();
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void cleanTempCertPreference() {
|
||||
|
@ -0,0 +1,308 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author BlueLine Labs, Inc.
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
|
||||
* Copyright (C) 2021 BlueLine Labs, Inc.
|
||||
* Copyright (C) 2020 Mario Danic (mario@lovelyhq.com)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.nextcloud.talk.controllers.base
|
||||
|
||||
import android.animation.AnimatorInflater
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.res.Resources
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.inputmethod.EditorInfo
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
import android.widget.EditText
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.appcompat.app.ActionBar
|
||||
import androidx.core.content.res.ResourcesCompat
|
||||
import autodagger.AutoInjector
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import com.bluelinelabs.conductor.ControllerChangeHandler
|
||||
import com.bluelinelabs.conductor.ControllerChangeType
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.activities.MainActivity
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
|
||||
import com.nextcloud.talk.controllers.AccountVerificationController
|
||||
import com.nextcloud.talk.controllers.ServerSelectionController
|
||||
import com.nextcloud.talk.controllers.SwitchAccountController
|
||||
import com.nextcloud.talk.controllers.WebViewLoginController
|
||||
import com.nextcloud.talk.controllers.base.providers.ActionBarProvider
|
||||
import com.nextcloud.talk.databinding.ActivityMainBinding
|
||||
import com.nextcloud.talk.utils.DisplayUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import java.util.ArrayList
|
||||
import javax.inject.Inject
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
@AutoInjector(NextcloudTalkApplication::class)
|
||||
abstract class NewBaseController(@LayoutRes var layoutRes: Int, args: Bundle? = null) : Controller(args) {
|
||||
enum class AppBarLayoutType {
|
||||
TOOLBAR, SEARCH_BAR, EMPTY
|
||||
}
|
||||
|
||||
@Inject
|
||||
@JvmField
|
||||
var appPreferences: AppPreferences? = null
|
||||
|
||||
@Inject
|
||||
@JvmField
|
||||
var context: Context? = null
|
||||
|
||||
protected open val title: String?
|
||||
get() = null
|
||||
|
||||
@Suppress("Detekt.TooGenericExceptionCaught")
|
||||
protected val actionBar: ActionBar?
|
||||
get() {
|
||||
var actionBarProvider: ActionBarProvider? = null
|
||||
if (this.activity is ActionBarProvider) {
|
||||
try {
|
||||
actionBarProvider = this.activity as ActionBarProvider?
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, "Failed to fetch the action bar provider", e)
|
||||
}
|
||||
}
|
||||
return actionBarProvider?.supportActionBar
|
||||
}
|
||||
|
||||
init {
|
||||
addLifecycleListener(object : LifecycleListener() {
|
||||
override fun postCreateView(controller: Controller, view: View) {
|
||||
onViewBound(view)
|
||||
actionBar?.let { setTitle() }
|
||||
}
|
||||
})
|
||||
cleanTempCertPreference()
|
||||
}
|
||||
|
||||
fun isAlive(): Boolean {
|
||||
return !isDestroyed && !isBeingDestroyed
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup,
|
||||
savedViewState: Bundle?
|
||||
): View {
|
||||
return inflater.inflate(layoutRes, container, false)
|
||||
}
|
||||
|
||||
protected open fun onViewBound(view: View) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && appPreferences!!.isKeyboardIncognito) {
|
||||
disableKeyboardPersonalisedLearning(view as ViewGroup)
|
||||
if (activity != null && activity is MainActivity) {
|
||||
val activity = activity as MainActivity?
|
||||
disableKeyboardPersonalisedLearning(activity!!.binding.appBar)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttach(view: View) {
|
||||
showSearchOrToolbar()
|
||||
setTitle()
|
||||
if (actionBar != null) {
|
||||
actionBar!!.setDisplayHomeAsUpEnabled(parentController != null || router.backstackSize > 1)
|
||||
}
|
||||
super.onAttach(view)
|
||||
}
|
||||
|
||||
protected fun showSearchOrToolbar() {
|
||||
if (isValidActivity(activity)) {
|
||||
val showSearchBar = appBarLayoutType == AppBarLayoutType.SEARCH_BAR
|
||||
val activity = activity as MainActivity
|
||||
|
||||
if (appBarLayoutType == AppBarLayoutType.EMPTY) {
|
||||
hideBars(activity.binding)
|
||||
} else {
|
||||
if (showSearchBar) {
|
||||
showSearchBar(activity.binding)
|
||||
} else {
|
||||
showToolbar(activity.binding)
|
||||
}
|
||||
colorizeStatusBar(showSearchBar, activity, resources)
|
||||
}
|
||||
|
||||
colorizeNavigationBar(activity, resources)
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidActivity(activity: Activity?): Boolean {
|
||||
return activity != null && activity is MainActivity
|
||||
}
|
||||
|
||||
private fun showSearchBar(binding: ActivityMainBinding) {
|
||||
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
|
||||
binding.searchToolbar.visibility = View.VISIBLE
|
||||
binding.searchText.hint = searchHint
|
||||
binding.toolbar.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.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
|
||||
binding.appBar.context,
|
||||
R.animator.appbar_elevation_off
|
||||
)
|
||||
binding.searchToolbar.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun showToolbar(binding: ActivityMainBinding) {
|
||||
val layoutParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
|
||||
binding.searchToolbar.visibility = View.GONE
|
||||
binding.toolbar.visibility = View.VISIBLE
|
||||
layoutParams.scrollFlags = 0
|
||||
binding.appBar.stateListAnimator = AnimatorInflater.loadStateListAnimator(
|
||||
binding.appBar.context,
|
||||
R.animator.appbar_elevation_on
|
||||
)
|
||||
binding.searchToolbar.layoutParams = layoutParams
|
||||
}
|
||||
|
||||
private fun hideBars(binding: ActivityMainBinding) {
|
||||
binding.toolbar.visibility = View.GONE
|
||||
binding.searchToolbar.visibility = View.GONE
|
||||
}
|
||||
|
||||
private fun colorizeStatusBar(showSearchBar: Boolean, activity: Activity?, resources: Resources?) {
|
||||
if (activity != null && resources != null) {
|
||||
if (showSearchBar) {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(
|
||||
resources, R.color.bg_default, null
|
||||
)
|
||||
)
|
||||
} else {
|
||||
DisplayUtils.applyColorToStatusBar(
|
||||
activity,
|
||||
ResourcesCompat.getColor(
|
||||
resources, R.color.appbar, null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun colorizeNavigationBar(activity: Activity?, resources: Resources?) {
|
||||
if (activity != null && resources != null) {
|
||||
DisplayUtils.applyColorToNavigationBar(
|
||||
activity.window,
|
||||
ResourcesCompat.getColor(resources, R.color.bg_default, null)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDetach(view: View) {
|
||||
super.onDetach(view)
|
||||
val imm = context!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
|
||||
imm.hideSoftInputFromWindow(view.windowToken, 0)
|
||||
}
|
||||
|
||||
protected fun setTitle() {
|
||||
if (isTitleSetable()) {
|
||||
run {
|
||||
calculateValidParentController()
|
||||
}
|
||||
actionBar!!.title = title
|
||||
}
|
||||
}
|
||||
|
||||
private fun calculateValidParentController() {
|
||||
var parentController = parentController
|
||||
while (parentController != null) {
|
||||
if (isValidController(parentController)) {
|
||||
return
|
||||
}
|
||||
parentController = parentController.parentController
|
||||
}
|
||||
}
|
||||
|
||||
private fun isValidController(parentController: Controller): Boolean {
|
||||
return parentController is BaseController && parentController.title != null
|
||||
}
|
||||
|
||||
private fun isTitleSetable(): Boolean {
|
||||
return title != null && actionBar != null
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (item.itemId == android.R.id.home) {
|
||||
router.popCurrentController()
|
||||
return true
|
||||
}
|
||||
return super.onOptionsItemSelected(item)
|
||||
}
|
||||
|
||||
override fun onChangeStarted(changeHandler: ControllerChangeHandler, changeType: ControllerChangeType) {
|
||||
super.onChangeStarted(changeHandler, changeType)
|
||||
if (changeType.isEnter && actionBar != null) {
|
||||
configureMenu(actionBar!!)
|
||||
}
|
||||
}
|
||||
|
||||
fun configureMenu(toolbar: ActionBar) {
|
||||
Intrinsics.checkNotNullParameter(toolbar, "toolbar")
|
||||
}
|
||||
|
||||
private fun cleanTempCertPreference() {
|
||||
sharedApplication!!.componentApplication.inject(this)
|
||||
val temporaryClassNames: MutableList<String> = ArrayList()
|
||||
temporaryClassNames.add(ServerSelectionController::class.java.name)
|
||||
temporaryClassNames.add(AccountVerificationController::class.java.name)
|
||||
temporaryClassNames.add(WebViewLoginController::class.java.name)
|
||||
temporaryClassNames.add(SwitchAccountController::class.java.name)
|
||||
if (!temporaryClassNames.contains(javaClass.name)) {
|
||||
appPreferences!!.removeTemporaryClientCertAlias()
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.O)
|
||||
private fun disableKeyboardPersonalisedLearning(viewGroup: ViewGroup) {
|
||||
var view: View?
|
||||
var editText: EditText
|
||||
for (i in 0 until viewGroup.childCount) {
|
||||
view = viewGroup.getChildAt(i)
|
||||
if (view is EditText) {
|
||||
editText = view
|
||||
editText.imeOptions = editText.imeOptions or EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
|
||||
} else if (view is ViewGroup) {
|
||||
disableKeyboardPersonalisedLearning(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open val appBarLayoutType: AppBarLayoutType
|
||||
get() = AppBarLayoutType.TOOLBAR
|
||||
val searchHint: String
|
||||
get() = context!!.getString(R.string.appbar_search_in, context!!.getString(R.string.nc_app_name))
|
||||
|
||||
companion object {
|
||||
private val TAG = BaseController::class.java.simpleName
|
||||
}
|
||||
}
|
@ -48,6 +48,7 @@ import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.events.BottomSheetLockEvent;
|
||||
import com.nextcloud.talk.interfaces.ConversationMenuInterface;
|
||||
import com.nextcloud.talk.jobs.LeaveConversationWorker;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.conversations.Conversation;
|
||||
import com.nextcloud.talk.utils.DisplayUtils;
|
||||
@ -151,7 +152,7 @@ public class CallMenuController extends BaseController implements FlexibleAdapte
|
||||
|
||||
if (conversation.isFavorite()) {
|
||||
menuItems.add(new MenuItem(getResources().getString(R.string.nc_remove_from_favorites), 97, DisplayUtils.getTintedDrawable(getResources(), R.drawable.ic_star_border_black_24dp, R.color.grey_600)));
|
||||
} else if (currentUser.hasSpreedFeatureCapability("favorites")) {
|
||||
} else if (CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "favorites")) {
|
||||
menuItems.add(new MenuItem(getResources().getString(R.string.nc_add_to_favorites)
|
||||
, 98, DisplayUtils.getTintedDrawable(getResources(), R.drawable.ic_star_black_24dp, R.color.grey_600)));
|
||||
}
|
||||
|
@ -34,8 +34,6 @@ import android.widget.ImageView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bluelinelabs.conductor.RouterTransaction;
|
||||
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler;
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
@ -46,6 +44,7 @@ import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.controllers.base.BaseController;
|
||||
import com.nextcloud.talk.events.BottomSheetLockEvent;
|
||||
import com.nextcloud.talk.models.RetrofitBucket;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.capabilities.Capabilities;
|
||||
import com.nextcloud.talk.models.json.capabilities.CapabilitiesOverall;
|
||||
@ -69,6 +68,7 @@ import java.util.ArrayList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import autodagger.AutoInjector;
|
||||
import butterknife.BindView;
|
||||
import io.reactivex.Observer;
|
||||
@ -157,6 +157,7 @@ public class OperationsMenuController extends BaseController {
|
||||
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected View inflateView(@NonNull LayoutInflater inflater, @NonNull ViewGroup container) {
|
||||
return inflater.inflate(R.layout.controller_operations_menu, container, false);
|
||||
@ -222,17 +223,23 @@ public class OperationsMenuController extends BaseController {
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<CapabilitiesOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
}
|
||||
|
||||
@SuppressLint("LongLogTag")
|
||||
@Override
|
||||
public void onNext(CapabilitiesOverall capabilitiesOverall) {
|
||||
public void onNext(@io.reactivex.annotations.NonNull CapabilitiesOverall capabilitiesOverall) {
|
||||
currentUser = new UserEntity();
|
||||
currentUser.setBaseUrl(baseUrl);
|
||||
currentUser.setUserId("?");
|
||||
try {
|
||||
currentUser.setCapabilities(LoganSquare.serialize(capabilitiesOverall.getOcs().getData().getCapabilities()));
|
||||
currentUser.setCapabilities(
|
||||
LoganSquare
|
||||
.serialize(
|
||||
capabilitiesOverall
|
||||
.getOcs()
|
||||
.getData()
|
||||
.getCapabilities()));
|
||||
} catch (IOException e) {
|
||||
Log.e("OperationsMenu", "Failed to serialize capabilities");
|
||||
}
|
||||
@ -248,7 +255,7 @@ public class OperationsMenuController extends BaseController {
|
||||
|
||||
@SuppressLint("LongLogTag")
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
showResultImage(false, false);
|
||||
Log.e(TAG, "Error fetching capabilities for guest", e);
|
||||
}
|
||||
@ -325,12 +332,12 @@ public class OperationsMenuController extends BaseController {
|
||||
.retry(1)
|
||||
.subscribe(new Observer<RoomOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
disposable = d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(RoomOverall roomOverall) {
|
||||
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
|
||||
conversation = roomOverall.getOcs().getData();
|
||||
if (conversation.isHasPassword() && conversation.isGuest()) {
|
||||
eventBus.post(new BottomSheetLockEvent(true, 0,
|
||||
@ -358,25 +365,27 @@ public class OperationsMenuController extends BaseController {
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<RoomOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
|
||||
public void onSubscribe(
|
||||
@io.reactivex.annotations.NonNull Disposable d
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(RoomOverall roomOverall) {
|
||||
public void onNext(
|
||||
@io.reactivex.annotations.NonNull RoomOverall roomOverall
|
||||
) {
|
||||
conversation = roomOverall.getOcs().getData();
|
||||
initiateConversation(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
showResultImage(false, false);
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
@ -385,7 +394,7 @@ public class OperationsMenuController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
showResultImage(false, false);
|
||||
dispose();
|
||||
}
|
||||
@ -418,12 +427,12 @@ public class OperationsMenuController extends BaseController {
|
||||
.retry(1)
|
||||
.subscribe(new Observer<RoomOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(RoomOverall roomOverall) {
|
||||
public void onNext(@io.reactivex.annotations.NonNull RoomOverall roomOverall) {
|
||||
conversation = roomOverall.getOcs().getData();
|
||||
|
||||
ncApi.getRoom(credentials,
|
||||
@ -433,18 +442,20 @@ public class OperationsMenuController extends BaseController {
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Observer<RoomOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(RoomOverall roomOverall) {
|
||||
public void onNext(
|
||||
@io.reactivex.annotations.NonNull RoomOverall roomOverall
|
||||
) {
|
||||
conversation = roomOverall.getOcs().getData();
|
||||
inviteUsersToAConversation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
showResultImage(false, false);
|
||||
dispose();
|
||||
}
|
||||
@ -458,7 +469,7 @@ public class OperationsMenuController extends BaseController {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
showResultImage(false, false);
|
||||
dispose();
|
||||
}
|
||||
@ -510,12 +521,16 @@ public class OperationsMenuController extends BaseController {
|
||||
private void showResultImage(boolean everythingOK, boolean isGuestSupportError) {
|
||||
progressBar.setVisibility(View.GONE);
|
||||
|
||||
if (everythingOK) {
|
||||
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(), R.drawable
|
||||
.ic_check_circle_black_24dp, R.color.nc_darkGreen));
|
||||
} else {
|
||||
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(), R.drawable
|
||||
.ic_cancel_black_24dp, R.color.nc_darkRed));
|
||||
if (getResources() != null) {
|
||||
if (everythingOK) {
|
||||
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(),
|
||||
R.drawable.ic_check_circle_black_24dp,
|
||||
R.color.nc_darkGreen));
|
||||
} else {
|
||||
resultImageView.setImageDrawable(DisplayUtils.getTintedDrawable(getResources(),
|
||||
R.drawable.ic_cancel_black_24dp,
|
||||
R.color.nc_darkRed));
|
||||
}
|
||||
}
|
||||
|
||||
resultImageView.setVisibility(View.VISIBLE);
|
||||
@ -581,59 +596,81 @@ public class OperationsMenuController extends BaseController {
|
||||
|
||||
int apiVersion = ApiUtils.getConversationApiVersion(currentUser, new int[] {4, 1});
|
||||
|
||||
if (localInvitedUsers.size() > 0 || (localInvitedGroups.size() > 0 && currentUser.hasSpreedFeatureCapability("invite-groups-and-mails"))) {
|
||||
if ((localInvitedGroups.size() > 0 && currentUser.hasSpreedFeatureCapability("invite-groups-and-mails"))) {
|
||||
for (int i = 0; i < localInvitedGroups.size(); i++) {
|
||||
final String groupId = localInvitedGroups.get(i);
|
||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipantWithSource(
|
||||
apiVersion,
|
||||
currentUser.getBaseUrl(),
|
||||
conversation.getToken(),
|
||||
"groups",
|
||||
groupId
|
||||
);
|
||||
if (localInvitedUsers.size() > 0 || (localInvitedGroups.size() > 0 &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails"))) {
|
||||
addGroupsToConversation(localInvitedUsers, localInvitedGroups, apiVersion);
|
||||
addUsersToConversation(localInvitedUsers, localInvitedGroups, apiVersion);
|
||||
} else {
|
||||
initiateConversation(true);
|
||||
}
|
||||
}
|
||||
|
||||
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.retry(1)
|
||||
.subscribe(new Observer<AddParticipantOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
private void addUsersToConversation(
|
||||
ArrayList<String> localInvitedUsers,
|
||||
ArrayList<String> localInvitedGroups,
|
||||
int apiVersion)
|
||||
{
|
||||
RetrofitBucket retrofitBucket;
|
||||
for (int i = 0; i < localInvitedUsers.size(); i++) {
|
||||
final String userId = invitedUsers.get(i);
|
||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(apiVersion,
|
||||
currentUser.getBaseUrl(),
|
||||
conversation.getToken(),
|
||||
userId);
|
||||
|
||||
}
|
||||
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.retry(1)
|
||||
.subscribe(new Observer<AddParticipantOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
|
||||
@Override
|
||||
public void onNext(AddParticipantOverall addParticipantOverall) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
dispose();
|
||||
}
|
||||
@Override
|
||||
public void onNext(
|
||||
@io.reactivex.annotations.NonNull AddParticipantOverall addParticipantOverall
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
synchronized (localInvitedGroups) {
|
||||
localInvitedGroups.remove(groupId);
|
||||
}
|
||||
@Override
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
|
||||
initiateConversation(true);
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onComplete() {
|
||||
synchronized (localInvitedUsers) {
|
||||
localInvitedUsers.remove(userId);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
|
||||
initiateConversation(true);
|
||||
}
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < localInvitedUsers.size(); i++) {
|
||||
final String userId = invitedUsers.get(i);
|
||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(apiVersion,
|
||||
currentUser.getBaseUrl(),
|
||||
conversation.getToken(),
|
||||
userId);
|
||||
private void addGroupsToConversation(
|
||||
ArrayList<String> localInvitedUsers,
|
||||
ArrayList<String> localInvitedGroups,
|
||||
int apiVersion)
|
||||
{
|
||||
RetrofitBucket retrofitBucket;
|
||||
if ((localInvitedGroups.size() > 0 &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(currentUser, "invite-groups-and-mails"))) {
|
||||
for (int i = 0; i < localInvitedGroups.size(); i++) {
|
||||
final String groupId = localInvitedGroups.get(i);
|
||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipantWithSource(
|
||||
apiVersion,
|
||||
currentUser.getBaseUrl(),
|
||||
conversation.getToken(),
|
||||
"groups",
|
||||
groupId
|
||||
);
|
||||
|
||||
ncApi.addParticipant(credentials, retrofitBucket.getUrl(), retrofitBucket.getQueryMap())
|
||||
.subscribeOn(Schedulers.io())
|
||||
@ -641,23 +678,25 @@ public class OperationsMenuController extends BaseController {
|
||||
.retry(1)
|
||||
.subscribe(new Observer<AddParticipantOverall>() {
|
||||
@Override
|
||||
public void onSubscribe(Disposable d) {
|
||||
public void onSubscribe(@io.reactivex.annotations.NonNull Disposable d) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNext(AddParticipantOverall addParticipantOverall) {
|
||||
public void onNext(
|
||||
@io.reactivex.annotations.NonNull AddParticipantOverall addParticipantOverall
|
||||
) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable e) {
|
||||
public void onError(@io.reactivex.annotations.NonNull Throwable e) {
|
||||
dispose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete() {
|
||||
synchronized (localInvitedUsers) {
|
||||
localInvitedUsers.remove(userId);
|
||||
synchronized (localInvitedGroups) {
|
||||
localInvitedGroups.remove(groupId);
|
||||
}
|
||||
|
||||
if (localInvitedGroups.size() == 0 && localInvitedUsers.size() == 0) {
|
||||
@ -666,9 +705,8 @@ public class OperationsMenuController extends BaseController {
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
} else {
|
||||
initiateConversation(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author BlueLine Labs, Inc.
|
||||
* Copyright (C) 2016 BlueLine Labs, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.nextcloud.talk.controllers.util
|
||||
|
||||
import android.view.View
|
||||
import androidx.lifecycle.LifecycleObserver
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.bluelinelabs.conductor.Controller
|
||||
import kotlin.properties.ReadOnlyProperty
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
fun <T : ViewBinding> Controller.viewBinding(bindingFactory: (View) -> T) =
|
||||
ControllerViewBindingDelegate(this, bindingFactory)
|
||||
|
||||
class ControllerViewBindingDelegate<T : ViewBinding>(
|
||||
controller: Controller,
|
||||
private val viewBinder: (View) -> T
|
||||
) : ReadOnlyProperty<Controller, T>, LifecycleObserver {
|
||||
|
||||
private var binding: T? = null
|
||||
|
||||
init {
|
||||
controller.addLifecycleListener(object : Controller.LifecycleListener() {
|
||||
override fun postDestroyView(controller: Controller) {
|
||||
binding = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun getValue(thisRef: Controller, property: KProperty<*>): T {
|
||||
return binding ?: viewBinder(thisRef.view!!).also { binding = it }
|
||||
}
|
||||
}
|
@ -241,7 +241,10 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
fun hasLinkedAccount(id: String): Boolean {
|
||||
var hasLinkedAccount = false
|
||||
val where =
|
||||
ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
ContactsContract.Data.MIMETYPE +
|
||||
" = ? AND " +
|
||||
ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID +
|
||||
" = ?"
|
||||
val params = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
|
||||
|
||||
val rawContactUri = ContactsContract.Data.CONTENT_URI
|
||||
@ -393,7 +396,10 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
private fun getDisplayNameFromDeviceContact(id: String?): String? {
|
||||
var displayName: String? = null
|
||||
val whereName =
|
||||
ContactsContract.Data.MIMETYPE + " = ? AND " + ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID + " = ?"
|
||||
ContactsContract.Data.MIMETYPE +
|
||||
" = ? AND " +
|
||||
ContactsContract.CommonDataKinds.StructuredName.CONTACT_ID +
|
||||
" = ?"
|
||||
val whereNameParams = arrayOf(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE, id)
|
||||
val nameCursor = context.contentResolver.query(
|
||||
ContactsContract.Data.CONTENT_URI,
|
||||
@ -405,7 +411,9 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
if (nameCursor != null) {
|
||||
while (nameCursor.moveToNext()) {
|
||||
displayName =
|
||||
nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME))
|
||||
nameCursor.getString(
|
||||
nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME)
|
||||
)
|
||||
}
|
||||
nameCursor.close()
|
||||
}
|
||||
@ -424,7 +432,11 @@ class ContactAddressBookWorker(val context: Context, workerParameters: WorkerPar
|
||||
|
||||
if (phonesNumbersCursor != null) {
|
||||
while (phonesNumbersCursor.moveToNext()) {
|
||||
numbers.add(phonesNumbersCursor.getString(phonesNumbersCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)))
|
||||
numbers.add(
|
||||
phonesNumbersCursor.getString(
|
||||
phonesNumbersCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)
|
||||
)
|
||||
)
|
||||
}
|
||||
phonesNumbersCursor.close()
|
||||
}
|
||||
|
@ -193,16 +193,16 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa
|
||||
|
||||
fun isStoragePermissionGranted(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
if (PermissionChecker.checkSelfPermission(
|
||||
return if (PermissionChecker.checkSelfPermission(
|
||||
context,
|
||||
Manifest.permission.WRITE_EXTERNAL_STORAGE
|
||||
) == PermissionChecker.PERMISSION_GRANTED
|
||||
) {
|
||||
Log.d(TAG, "Permission is granted")
|
||||
return true
|
||||
true
|
||||
} else {
|
||||
Log.d(TAG, "Permission is revoked")
|
||||
return false
|
||||
false
|
||||
}
|
||||
} else { // permission is automatically granted on sdk<23 upon installation
|
||||
Log.d(TAG, "Permission is granted")
|
||||
|
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Andy Scherzinger
|
||||
* @author Mario Danic
|
||||
* Copyright (C) 2021 Andy Scherzinger (info@andy-scherzinger.de)
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.nextcloud.talk.models.database;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
import com.nextcloud.talk.models.json.capabilities.Capabilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public abstract class CapabilitiesUtil {
|
||||
private static final String TAG = CapabilitiesUtil.class.getSimpleName();
|
||||
|
||||
public static boolean hasNotificationsCapability(@Nullable UserEntity user, String capabilityName) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities.getNotificationsCapability() != null &&
|
||||
capabilities.getNotificationsCapability().getFeatures() != null) {
|
||||
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasExternalCapability(@Nullable UserEntity user, String capabilityName) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities.getExternalCapability() != null &&
|
||||
capabilities.getExternalCapability().containsKey("v1")) {
|
||||
return capabilities.getExternalCapability().get("v1").contains("capabilityName");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isServerEOL(@Nullable UserEntity user) {
|
||||
// Capability is available since Talk 4 => Nextcloud 14 => Autmn 2018
|
||||
return !hasSpreedFeatureCapability(user, "no-ping");
|
||||
}
|
||||
|
||||
public static boolean isServerAlmostEOL(@Nullable UserEntity user) {
|
||||
// Capability is available since Talk 8 => Nextcloud 18 => January 2020
|
||||
return !hasSpreedFeatureCapability(user, "chat-replies");
|
||||
}
|
||||
|
||||
public static boolean hasSpreedFeatureCapability(@Nullable UserEntity user, String capabilityName) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null && capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null) {
|
||||
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Integer getMessageMaxLength(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
HashMap<String, String> chatConfigHashMap = capabilities
|
||||
.getSpreedCapability()
|
||||
.getConfig()
|
||||
.get("chat");
|
||||
if (chatConfigHashMap != null && chatConfigHashMap.containsKey("max-length")) {
|
||||
int chatSize = Integer.parseInt(chatConfigHashMap.get("max-length"));
|
||||
if (chatSize > 0) {
|
||||
return chatSize;
|
||||
} else {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
public static boolean isPhoneBookIntegrationAvailable(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
return capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures().contains("phonebook-search");
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isReadStatusAvailable(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
Map<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
|
||||
return map != null && map.containsKey("read-privacy");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isReadStatusPrivate(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
|
||||
if (map != null && map.containsKey("read-privacy")) {
|
||||
return Integer.parseInt(map.get("read-privacy")) == 1;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String getAttachmentFolder(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("attachments")) {
|
||||
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("attachments");
|
||||
if (map != null && map.containsKey("folder")) {
|
||||
return map.get("folder");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get attachment folder", e);
|
||||
}
|
||||
}
|
||||
return "/Talk";
|
||||
}
|
||||
|
||||
public static String getServerName(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null && capabilities.getThemingCapability() != null) {
|
||||
return capabilities.getThemingCapability().getName();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get server name", e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// TODO later avatar can also be checked via user fields, for now it is in Talk capability
|
||||
public static boolean isAvatarEndpointAvailable(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
return (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures().contains("temp-user-avatar-api"));
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get server name", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean canEditScopes(@Nullable UserEntity user) {
|
||||
if (user != null && user.getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(user.getCapabilities(), Capabilities.class);
|
||||
return (capabilities != null &&
|
||||
capabilities.getProvisioningCapability() != null &&
|
||||
capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() != null &&
|
||||
capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() > 1);
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get server name", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
* Nextcloud Talk application
|
||||
*
|
||||
* @author Mario Danic
|
||||
* @author Andy Scherzinger
|
||||
* Copyright (C) 2021 Andy Scherzinger <info@andy-scherzinger.de>
|
||||
* Copyright (C) 2017-2018 Mario Danic <mario@lovelyhq.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -20,14 +22,8 @@
|
||||
package com.nextcloud.talk.models.database;
|
||||
|
||||
import android.os.Parcelable;
|
||||
import android.util.Log;
|
||||
|
||||
import com.bluelinelabs.logansquare.LoganSquare;
|
||||
import com.nextcloud.talk.models.json.capabilities.Capabilities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
import io.requery.Entity;
|
||||
import io.requery.Generated;
|
||||
@ -36,7 +32,7 @@ import io.requery.Persistable;
|
||||
|
||||
@Entity
|
||||
public interface User extends Parcelable, Persistable, Serializable {
|
||||
static final String TAG = "UserEntity";
|
||||
String TAG = "UserEntity";
|
||||
|
||||
@Key
|
||||
@Generated
|
||||
@ -63,206 +59,4 @@ public interface User extends Parcelable, Persistable, Serializable {
|
||||
boolean getCurrent();
|
||||
|
||||
boolean getScheduledForDeletion();
|
||||
|
||||
default boolean hasNotificationsCapability(String capabilityName) {
|
||||
if (getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities.getNotificationsCapability() != null && capabilities.getNotificationsCapability().getFeatures() != null) {
|
||||
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean hasExternalCapability(String capabilityName) {
|
||||
if (getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities.getExternalCapability() != null && capabilities.getExternalCapability().containsKey("v1")) {
|
||||
return capabilities.getExternalCapability().get("v1").contains("capabilityName");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isServerEOL() {
|
||||
// Capability is available since Talk 4 => Nextcloud 14 => Autmn 2018
|
||||
return !hasSpreedFeatureCapability("no-ping");
|
||||
}
|
||||
|
||||
default boolean isServerAlmostEOL() {
|
||||
// Capability is available since Talk 8 => Nextcloud 18 => January 2020
|
||||
return !hasSpreedFeatureCapability("chat-replies");
|
||||
}
|
||||
|
||||
default boolean hasSpreedFeatureCapability(String capabilityName) {
|
||||
if (getCapabilities() != null) {
|
||||
try {
|
||||
Capabilities capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null && capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null) {
|
||||
return capabilities.getSpreedCapability().getFeatures().contains(capabilityName);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Failed to get capabilities for the user");
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default int getMessageMaxLength() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities = null;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null && capabilities.getSpreedCapability() != null && capabilities.getSpreedCapability().getConfig() != null
|
||||
&& capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
HashMap<String, String> chatConfigHashMap = capabilities.getSpreedCapability().getConfig().get("chat");
|
||||
if (chatConfigHashMap != null && chatConfigHashMap.containsKey("max-length")) {
|
||||
int chatSize = Integer.parseInt(chatConfigHashMap.get("max-length"));
|
||||
if (chatSize > 0) {
|
||||
return chatSize;
|
||||
} else {
|
||||
return 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return 1000;
|
||||
}
|
||||
|
||||
default boolean isPhoneBookIntegrationAvailable() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
return capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures().contains("phonebook-search");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isReadStatusAvailable() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
|
||||
return map != null && map.containsKey("read-privacy");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean isReadStatusPrivate() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("chat")) {
|
||||
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("chat");
|
||||
if (map != null && map.containsKey("read-privacy")) {
|
||||
return Integer.parseInt(map.get("read-privacy")) == 1;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default String getAttachmentFolder() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getConfig() != null &&
|
||||
capabilities.getSpreedCapability().getConfig().containsKey("attachments")) {
|
||||
HashMap<String, String> map = capabilities.getSpreedCapability().getConfig().get("attachments");
|
||||
if (map != null && map.containsKey("folder")) {
|
||||
return map.get("folder");
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get attachment folder", e);
|
||||
}
|
||||
}
|
||||
return "/Talk";
|
||||
}
|
||||
|
||||
default String getServerName() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
if (capabilities != null && capabilities.getThemingCapability() != null) {
|
||||
return capabilities.getThemingCapability().getName();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.e("User.java", "Failed to get server name", e);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// TODO later avatar can also be checked via user fields, for now it is in Talk capability
|
||||
default boolean isAvatarEndpointAvailable() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
return (capabilities != null &&
|
||||
capabilities.getSpreedCapability() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures() != null &&
|
||||
capabilities.getSpreedCapability().getFeatures().contains("temp-user-avatar-api"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default boolean canEditScopes() {
|
||||
if (getCapabilities() != null) {
|
||||
Capabilities capabilities;
|
||||
try {
|
||||
capabilities = LoganSquare.parse(getCapabilities(), Capabilities.class);
|
||||
return (capabilities != null &&
|
||||
capabilities.getProvisioningCapability() != null &&
|
||||
capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() != null &&
|
||||
capabilities.getProvisioningCapability().getAccountPropertyScopesVersion() > 1);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package com.nextcloud.talk.models.json.conversations;
|
||||
|
||||
import com.bluelinelabs.logansquare.annotation.JsonField;
|
||||
import com.bluelinelabs.logansquare.annotation.JsonObject;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.chat.ChatMessage;
|
||||
import com.nextcloud.talk.models.json.converters.EnumLobbyStateConverter;
|
||||
@ -108,7 +109,8 @@ public class Conversation {
|
||||
}
|
||||
|
||||
private boolean isLockedOneToOne(UserEntity conversationUser) {
|
||||
return (getType() == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL && conversationUser.hasSpreedFeatureCapability("locked-one-to-one-rooms"));
|
||||
return (getType() == ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "locked-one-to-one-rooms"));
|
||||
}
|
||||
|
||||
public boolean canModerate(UserEntity conversationUser) {
|
||||
|
@ -100,8 +100,7 @@ public class NotificationRichObject {
|
||||
final Object $type = this.getType();
|
||||
result = result * PRIME + ($type == null ? 43 : $type.hashCode());
|
||||
final Object $name = this.getName();
|
||||
result = result * PRIME + ($name == null ? 43 : $name.hashCode());
|
||||
return result;
|
||||
return result * PRIME + ($name == null ? 43 : $name.hashCode());
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
|
@ -71,8 +71,10 @@ class PackageReplacedReceiver : BroadcastReceiver() {
|
||||
}
|
||||
|
||||
if (!appPreferences.isNotificationChannelUpgradedToV3 && packageInfo.versionCode > 51) {
|
||||
notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V2)
|
||||
notificationManager.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2)
|
||||
notificationManager
|
||||
.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V2)
|
||||
notificationManager
|
||||
.deleteNotificationChannel(NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V2)
|
||||
appPreferences.setNotificationChannelIsUpgradedToV3(true)
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.nextcloud.talk.R
|
||||
import com.nextcloud.talk.components.filebrowser.controllers.BrowserController
|
||||
import com.nextcloud.talk.controllers.ChatController
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil
|
||||
|
||||
class AttachmentDialog(val activity: Activity, var chatController: ChatController) : BottomSheetDialog(activity) {
|
||||
|
||||
@ -51,7 +52,7 @@ class AttachmentDialog(val activity: Activity, var chatController: ChatControlle
|
||||
window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
|
||||
unbinder = ButterKnife.bind(this, view)
|
||||
|
||||
var serverName = chatController.conversationUser?.serverName
|
||||
var serverName = CapabilitiesUtil.getServerName(chatController.conversationUser)
|
||||
attachFromCloud?.text = chatController.resources?.let {
|
||||
if (serverName.isNullOrEmpty()) {
|
||||
serverName = it.getString(R.string.nc_server_product_name)
|
||||
|
@ -55,8 +55,14 @@ object AccountUtils {
|
||||
internalUserEntity = userEntitiesList[i]
|
||||
importAccount = getInformationFromAccount(account)
|
||||
if (importAccount.token != null) {
|
||||
if (importAccount.baseUrl.startsWith("http://") || importAccount.baseUrl.startsWith("https://")) {
|
||||
if (internalUserEntity.username == importAccount.username && internalUserEntity.baseUrl == importAccount.baseUrl) {
|
||||
if (
|
||||
importAccount.baseUrl.startsWith("http://") ||
|
||||
importAccount.baseUrl.startsWith("https://")
|
||||
) {
|
||||
if (
|
||||
internalUserEntity.username == importAccount.username &&
|
||||
internalUserEntity.baseUrl == importAccount.baseUrl
|
||||
) {
|
||||
accountFound = true
|
||||
break
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import com.nextcloud.talk.BuildConfig;
|
||||
import com.nextcloud.talk.R;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.models.RetrofitBucket;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -115,7 +116,7 @@ public class ApiUtils {
|
||||
return getConversationApiVersion(capabilities, versions);
|
||||
}
|
||||
|
||||
public static int getConversationApiVersion(UserEntity capabilities, int[] versions) throws NoSupportedApiException {
|
||||
public static int getConversationApiVersion(UserEntity user, int[] versions) throws NoSupportedApiException {
|
||||
boolean hasApiV4 = false;
|
||||
for (int version : versions) {
|
||||
hasApiV4 |= version == 4;
|
||||
@ -127,16 +128,17 @@ public class ApiUtils {
|
||||
}
|
||||
|
||||
for (int version : versions) {
|
||||
if (capabilities.hasSpreedFeatureCapability("conversation-v" + version)) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation-v" + version)) {
|
||||
return version;
|
||||
}
|
||||
|
||||
// Fallback for old API versions
|
||||
if ((version == 1 || version == 2)) {
|
||||
if (capabilities.hasSpreedFeatureCapability("conversation-v2")) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation-v2")) {
|
||||
return version;
|
||||
}
|
||||
if (version == 1 && capabilities.hasSpreedFeatureCapability("conversation")) {
|
||||
if (version == 1 &&
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(user, "conversation")) {
|
||||
return version;
|
||||
}
|
||||
}
|
||||
@ -144,20 +146,20 @@ public class ApiUtils {
|
||||
throw new NoSupportedApiException();
|
||||
}
|
||||
|
||||
public static int getSignalingApiVersion(UserEntity capabilities, int[] versions) throws NoSupportedApiException {
|
||||
public static int getSignalingApiVersion(UserEntity user, int[] versions) throws NoSupportedApiException {
|
||||
for (int version : versions) {
|
||||
if (capabilities.hasSpreedFeatureCapability("signaling-v" + version)) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(user, "signaling-v" + version)) {
|
||||
return version;
|
||||
}
|
||||
|
||||
if (version == 2 &&
|
||||
capabilities.hasSpreedFeatureCapability("sip-support") &&
|
||||
!capabilities.hasSpreedFeatureCapability("signaling-v3")) {
|
||||
CapabilitiesUtil.hasSpreedFeatureCapability(user, "sip-support") &&
|
||||
!CapabilitiesUtil.hasSpreedFeatureCapability(user, "signaling-v3")) {
|
||||
return version;
|
||||
}
|
||||
|
||||
if (version == 1 &&
|
||||
!capabilities.hasSpreedFeatureCapability("signaling-v3")) {
|
||||
!CapabilitiesUtil.hasSpreedFeatureCapability(user, "signaling-v3")) {
|
||||
// Has no capability, we just assume it is always there when there is no v3 or later
|
||||
return version;
|
||||
}
|
||||
@ -165,9 +167,9 @@ public class ApiUtils {
|
||||
throw new NoSupportedApiException();
|
||||
}
|
||||
|
||||
public static int getChatApiVersion(UserEntity capabilities, int[] versions) throws NoSupportedApiException {
|
||||
public static int getChatApiVersion(UserEntity user, int[] versions) throws NoSupportedApiException {
|
||||
for (int version : versions) {
|
||||
if (version == 1 && capabilities.hasSpreedFeatureCapability("chat-v2")) {
|
||||
if (version == 1 && CapabilitiesUtil.hasSpreedFeatureCapability(user, "chat-v2")) {
|
||||
// Do not question that chat-v2 capability shows the availability of api/v1/ endpoint *see no evil*
|
||||
return version;
|
||||
}
|
||||
|
@ -85,7 +85,10 @@ object NotificationUtils {
|
||||
|
||||
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && notificationManager.getNotificationChannel(channelId) == null) {
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
|
||||
notificationManager.getNotificationChannel(channelId) == null
|
||||
) {
|
||||
|
||||
val channel = NotificationChannel(
|
||||
channelId, channelName,
|
||||
@ -156,9 +159,9 @@ object NotificationUtils {
|
||||
notification = statusBarNotification.notification
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(
|
||||
BundleKeys.KEY_NOTIFICATION_ID
|
||||
)
|
||||
if (
|
||||
conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) &&
|
||||
notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)
|
||||
) {
|
||||
notificationManager.cancel(statusBarNotification.id)
|
||||
}
|
||||
@ -184,9 +187,9 @@ object NotificationUtils {
|
||||
notification = statusBarNotification.notification
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) && roomTokenOrId == statusBarNotification.notification.extras.getString(
|
||||
BundleKeys.KEY_ROOM_TOKEN
|
||||
)
|
||||
if (
|
||||
conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) &&
|
||||
roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)
|
||||
) {
|
||||
return statusBarNotification
|
||||
}
|
||||
@ -202,7 +205,9 @@ object NotificationUtils {
|
||||
conversationUser: UserEntity,
|
||||
roomTokenOrId: String
|
||||
) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && conversationUser.id != -1L &&
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
|
||||
conversationUser.id != -1L &&
|
||||
context != null
|
||||
) {
|
||||
|
||||
@ -215,9 +220,7 @@ object NotificationUtils {
|
||||
|
||||
if (notification != null && !notification.extras.isEmpty) {
|
||||
if (conversationUser.id == notification.extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) &&
|
||||
roomTokenOrId == statusBarNotification.notification.extras.getString(
|
||||
BundleKeys.KEY_ROOM_TOKEN
|
||||
)
|
||||
roomTokenOrId == statusBarNotification.notification.extras.getString(BundleKeys.KEY_ROOM_TOKEN)
|
||||
) {
|
||||
notificationManager.cancel(statusBarNotification.id)
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import autodagger.AutoInjector;
|
||||
import com.nextcloud.talk.api.NcApi;
|
||||
import com.nextcloud.talk.application.NextcloudTalkApplication;
|
||||
import com.nextcloud.talk.models.database.ArbitraryStorageEntity;
|
||||
import com.nextcloud.talk.models.database.CapabilitiesUtil;
|
||||
import com.nextcloud.talk.models.database.UserEntity;
|
||||
import com.nextcloud.talk.models.json.generic.GenericOverall;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
@ -76,7 +77,7 @@ public class DatabaseStorageModule implements StorageModule {
|
||||
if (!key.equals("message_notification_level")) {
|
||||
arbitraryStorageUtils.storeStorageSetting(accountIdentifier, key, value, conversationToken);
|
||||
} else {
|
||||
if (conversationUser.hasSpreedFeatureCapability("notification-levels")) {
|
||||
if (CapabilitiesUtil.hasSpreedFeatureCapability(conversationUser, "notification-levels")) {
|
||||
if (!TextUtils.isEmpty(messageNotificationLevel) && !messageNotificationLevel.equals(value)) {
|
||||
int intValue;
|
||||
switch (value) {
|
||||
|
@ -26,7 +26,9 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@color/bg_default">
|
||||
|
||||
<include layout="@layout/lobby_view"
|
||||
<include
|
||||
android:id="@+id/lobby"
|
||||
layout="@layout/lobby_view"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"/>
|
||||
|
||||
|
@ -128,7 +128,7 @@
|
||||
android:id="@+id/participants_list_category"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/webinar_settings"
|
||||
android:layout_below="@+id/settings"
|
||||
android:visibility="gone"
|
||||
apc:cardBackgroundColor="@color/bg_default"
|
||||
apc:cardElevation="0dp"
|
||||
@ -180,21 +180,30 @@
|
||||
|
||||
</com.yarolegovich.mp.MaterialPreferenceCategory>
|
||||
|
||||
<include
|
||||
layout="@layout/notification_settings_item"
|
||||
<LinearLayout
|
||||
android:id="@+id/settings"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/otherRoomOptions"
|
||||
android:visibility="gone"
|
||||
tools:visibility="gone" />
|
||||
android:orientation="vertical">
|
||||
|
||||
<include
|
||||
layout="@layout/webinar_info_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/notification_settings"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
<include
|
||||
android:id="@+id/notification_settings_view"
|
||||
layout="@layout/notification_settings_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="gone" />
|
||||
|
||||
<include
|
||||
android:id="@+id/webinar_info_view"
|
||||
layout="@layout/webinar_info_item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
</RelativeLayout>
|
||||
|
@ -1,5 +1,5 @@
|
||||
build:
|
||||
maxIssues: 346
|
||||
maxIssues: 201
|
||||
weights:
|
||||
# complexity: 2
|
||||
# LongParameterList: 1
|
||||
|
@ -1 +1 @@
|
||||
457
|
||||
450
|
@ -1,2 +1,2 @@
|
||||
DO NOT TOUCH; GENERATED BY DRONE
|
||||
<span class="mdl-layout-title">Lint Report: 3 errors and 329 warnings</span>
|
||||
<span class="mdl-layout-title">Lint Report: 3 errors and 290 warnings</span>
|
||||
|
Loading…
Reference in New Issue
Block a user