mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
[settings-sync] IJPL-188452: Use combobox for account selector dropdown
- Account selector now follows the design - Add checkbox indicating selected account - Add provider icon - Handle logging out from an active account (disable sync and switch to another account) (cherry picked from commit 7549862a1acb9e902a636e0e98c26b45275bb49b) IJ-CR-174183 GitOrigin-RevId: c8aa48ab8325db9070442b2b80fd115c9d26bff9
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3806d403d2
commit
9737a5e6c2
@@ -60,7 +60,7 @@ enable.dialog.change=Change
|
|||||||
enable.sync.check.server.data.progress=Checking server data\u2026
|
enable.sync.check.server.data.progress=Checking server data\u2026
|
||||||
enable.sync.get.from.server.progress=Getting Settings from Server\u2026
|
enable.sync.get.from.server.progress=Getting Settings from Server\u2026
|
||||||
enable.sync.push.to.server.progress=Pushing Settings to Server\u2026
|
enable.sync.push.to.server.progress=Pushing Settings to Server\u2026
|
||||||
enable.sync.add.account=Add Account
|
enable.sync.add.account=Add Account\u2026
|
||||||
enable.sync.choose.data.provider.title=Choose Provider
|
enable.sync.choose.data.provider.title=Choose Provider
|
||||||
enable.sync.choose.data.provider.text=Please select a provider that will store and process your data.
|
enable.sync.choose.data.provider.text=Please select a provider that will store and process your data.
|
||||||
# {0} - name of the provider - JetBrains or Google
|
# {0} - name of the provider - JetBrains or Google
|
||||||
@@ -82,7 +82,7 @@ status.action.settings.sync.is.off=Off
|
|||||||
status.action.settings.sync.is.on=On
|
status.action.settings.sync.is.on=On
|
||||||
status.action.settings.sync.failed=Failed
|
status.action.settings.sync.failed=Failed
|
||||||
status.action.settings.sync.pending.action=Action Required
|
status.action.settings.sync.pending.action=Action Required
|
||||||
logout.link.text=Log out {0} Account
|
logout.link.text=Log Out {0} Account\u2026
|
||||||
# logout.dialog.title=Confirm Log Out
|
# logout.dialog.title=Confirm Log Out
|
||||||
# logout.dialog.message=Are you sure you want to log out?
|
# logout.dialog.message=Are you sure you want to log out?
|
||||||
# logout.dialog.button=Log Out
|
# logout.dialog.button=Log Out
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ package com.intellij.settingsSync.core.config
|
|||||||
import com.intellij.BundleBase
|
import com.intellij.BundleBase
|
||||||
import com.intellij.CommonBundle
|
import com.intellij.CommonBundle
|
||||||
import com.intellij.icons.AllIcons
|
import com.intellij.icons.AllIcons
|
||||||
import com.intellij.ide.DataManager
|
|
||||||
import com.intellij.openapi.actionSystem.*
|
import com.intellij.openapi.actionSystem.*
|
||||||
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
import com.intellij.openapi.actionSystem.ex.ActionUtil
|
||||||
import com.intellij.openapi.application.EDT
|
import com.intellij.openapi.application.EDT
|
||||||
@@ -20,14 +19,11 @@ import com.intellij.openapi.options.BoundConfigurable
|
|||||||
import com.intellij.openapi.options.Configurable
|
import com.intellij.openapi.options.Configurable
|
||||||
import com.intellij.openapi.options.ConfigurableProvider
|
import com.intellij.openapi.options.ConfigurableProvider
|
||||||
import com.intellij.openapi.project.DumbAwareAction
|
import com.intellij.openapi.project.DumbAwareAction
|
||||||
|
import com.intellij.openapi.ui.ComboBox
|
||||||
import com.intellij.openapi.ui.DialogPanel
|
import com.intellij.openapi.ui.DialogPanel
|
||||||
import com.intellij.openapi.ui.DialogWrapper
|
import com.intellij.openapi.ui.DialogWrapper
|
||||||
import com.intellij.openapi.ui.MessageDialogBuilder.Companion.yesNo
|
import com.intellij.openapi.ui.MessageDialogBuilder.Companion.yesNo
|
||||||
import com.intellij.openapi.ui.Messages
|
import com.intellij.openapi.ui.Messages
|
||||||
import com.intellij.openapi.ui.popup.JBPopup
|
|
||||||
import com.intellij.openapi.ui.popup.ListSeparator
|
|
||||||
import com.intellij.openapi.ui.popup.PopupStep
|
|
||||||
import com.intellij.openapi.ui.popup.util.BaseListPopupStep
|
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
import com.intellij.openapi.util.IntellijInternalApi
|
import com.intellij.openapi.util.IntellijInternalApi
|
||||||
import com.intellij.openapi.util.text.HtmlBuilder
|
import com.intellij.openapi.util.text.HtmlBuilder
|
||||||
@@ -45,29 +41,25 @@ import com.intellij.settingsSync.core.communicator.SettingsSyncUserData
|
|||||||
import com.intellij.settingsSync.core.communicator.getAvailableSyncProviders
|
import com.intellij.settingsSync.core.communicator.getAvailableSyncProviders
|
||||||
import com.intellij.settingsSync.core.config.SettingsSyncEnabler.State
|
import com.intellij.settingsSync.core.config.SettingsSyncEnabler.State
|
||||||
import com.intellij.settingsSync.core.statistics.SettingsSyncEventsStatistics
|
import com.intellij.settingsSync.core.statistics.SettingsSyncEventsStatistics
|
||||||
import com.intellij.ui.RelativeFont
|
import com.intellij.ui.MutableCollectionComboBoxModel
|
||||||
import com.intellij.ui.components.DropDownLink
|
import com.intellij.ui.SimpleTextAttributes
|
||||||
import com.intellij.ui.components.JBHtmlPane
|
import com.intellij.ui.components.JBHtmlPane
|
||||||
import com.intellij.ui.components.JBRadioButton
|
import com.intellij.ui.components.JBRadioButton
|
||||||
import com.intellij.ui.dsl.builder.*
|
import com.intellij.ui.dsl.builder.*
|
||||||
import com.intellij.ui.dsl.builder.components.DslLabel
|
import com.intellij.ui.dsl.listCellRenderer.listCellRenderer
|
||||||
import com.intellij.ui.dsl.builder.components.DslLabelType
|
|
||||||
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
|
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
|
||||||
import com.intellij.ui.layout.ComponentPredicate
|
import com.intellij.ui.layout.ComponentPredicate
|
||||||
import com.intellij.ui.layout.and
|
import com.intellij.ui.layout.and
|
||||||
import com.intellij.ui.layout.not
|
import com.intellij.ui.layout.not
|
||||||
import com.intellij.ui.layout.selected
|
import com.intellij.ui.layout.selected
|
||||||
import com.intellij.ui.popup.list.ListPopupImpl
|
|
||||||
import com.intellij.ui.scale.JBUIScale.scale
|
|
||||||
import com.intellij.util.Consumer
|
import com.intellij.util.Consumer
|
||||||
import com.intellij.util.asDisposable
|
import com.intellij.util.asDisposable
|
||||||
|
import com.intellij.util.IconUtil
|
||||||
import com.intellij.util.text.DateFormatUtil
|
import com.intellij.util.text.DateFormatUtil
|
||||||
import com.intellij.util.ui.JBFont
|
import com.intellij.util.ui.JBFont
|
||||||
import com.intellij.util.ui.JBUI
|
import com.intellij.util.ui.JBUI
|
||||||
import com.intellij.util.ui.NamedColorUtil
|
import com.intellij.util.ui.NamedColorUtil
|
||||||
import com.intellij.util.ui.StartupUiUtil.labelFont
|
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.awt.event.ItemEvent
|
|
||||||
import java.awt.event.MouseAdapter
|
import java.awt.event.MouseAdapter
|
||||||
import java.awt.event.MouseEvent
|
import java.awt.event.MouseEvent
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
@@ -85,18 +77,21 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
|
|
||||||
private lateinit var configPanel: DialogPanel
|
private lateinit var configPanel: DialogPanel
|
||||||
private lateinit var enableCheckbox: JCheckBox
|
private lateinit var enableCheckbox: JCheckBox
|
||||||
private lateinit var cellDropDownLink: Cell<DropDownLink<UserProviderHolder?>>
|
|
||||||
private lateinit var userDropDownLink: DropDownLink<UserProviderHolder?>
|
private val userAccountsList = arrayListOf<UserProviderHolder>()
|
||||||
|
private var userAccountsLogout: UserProviderHolder? = null
|
||||||
|
private val userComboBoxModel = MutableCollectionComboBoxModel<UserProviderHolder>()
|
||||||
|
private var userProviderHolder: UserProviderHolder? = currentUser()
|
||||||
|
private lateinit var cellUserComboBox: Cell<ComboBox<UserProviderHolder>>
|
||||||
|
|
||||||
private lateinit var syncTypeLabel: JBHtmlPane
|
private lateinit var syncTypeLabel: JBHtmlPane
|
||||||
private lateinit var syncConfigPanel: DialogPanel
|
private lateinit var syncConfigPanel: DialogPanel
|
||||||
|
|
||||||
|
|
||||||
private val syncEnabler = SettingsSyncEnabler()
|
private val syncEnabler = SettingsSyncEnabler()
|
||||||
private val enableSyncOption = AtomicProperty<InitSyncType>(InitSyncType.GET_FROM_SERVER)
|
private val enableSyncOption = AtomicProperty<InitSyncType>(InitSyncType.GET_FROM_SERVER)
|
||||||
private val disableSyncOption = AtomicProperty<DisableSyncType>(DisableSyncType.DISABLE)
|
private val disableSyncOption = AtomicProperty<DisableSyncType>(DisableSyncType.DISABLE)
|
||||||
private val remoteSettingsExist = AtomicBooleanProperty(false)
|
private val remoteSettingsExist = AtomicBooleanProperty(false)
|
||||||
private val wasUsedBefore = AtomicBooleanProperty(currentUser() != null)
|
private val wasUsedBefore = AtomicBooleanProperty(currentUser() != null)
|
||||||
private val userAccountsList = arrayListOf<UserProviderHolder>()
|
|
||||||
private val userAccountListIsNotEmpty = AtomicBooleanProperty(false)
|
private val userAccountListIsNotEmpty = AtomicBooleanProperty(false)
|
||||||
private val syncPanelHolder = SettingsSyncPanelHolder()
|
private val syncPanelHolder = SettingsSyncPanelHolder()
|
||||||
private val hasMultipleProviders = AtomicBooleanProperty(RemoteCommunicatorHolder.getExternalProviders().isNotEmpty())
|
private val hasMultipleProviders = AtomicBooleanProperty(RemoteCommunicatorHolder.getExternalProviders().isNotEmpty())
|
||||||
@@ -120,13 +115,19 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
SettingsSyncEvents.getInstance().removeListener(this)
|
SettingsSyncEvents.getInstance().removeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun currentUserId() = SettingsSyncLocalSettings.getInstance().userId
|
||||||
|
|
||||||
private fun currentUser(): UserProviderHolder? {
|
private fun currentUser(): UserProviderHolder? {
|
||||||
val userId = SettingsSyncLocalSettings.getInstance().userId ?: return null
|
val userId = currentUserId() ?: return null
|
||||||
val providerCode = SettingsSyncLocalSettings.getInstance().providerCode ?: return null
|
val providerCode = SettingsSyncLocalSettings.getInstance().providerCode ?: return null
|
||||||
val authService = RemoteCommunicatorHolder.getProvider(providerCode)?.authService ?: return null
|
val authService = RemoteCommunicatorHolder.getProvider(providerCode)?.authService ?: return null
|
||||||
return authService.getAvailableUserAccounts().find {
|
return authService.getAvailableUserAccounts().find {
|
||||||
it.id == userId
|
it.id == userId
|
||||||
}?.toUserProviderHolder(authService.providerName)
|
}?.toUserProviderHolder(authService.providerName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun selectedUser(): UserProviderHolder? {
|
||||||
|
return userComboBoxModel.selectedItem as? UserProviderHolder
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createPanel(): DialogPanel {
|
override fun createPanel(): DialogPanel {
|
||||||
@@ -136,8 +137,11 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
|
|
||||||
configPanel = panel {
|
configPanel = panel {
|
||||||
updateUserAccountsList()
|
updateUserAccountsList()
|
||||||
val userProviderHolder: UserProviderHolder? = currentUser() ?: userAccountsList.firstOrNull { it != UserProviderHolder.addAccount }
|
validateCurrentUser()
|
||||||
val authService = userProviderHolder?.let { RemoteCommunicatorHolder.getProvider(userProviderHolder.providerCode) } ?.authService
|
updateUserAccountLogout(userProviderHolder)
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
|
updateUserComboBoxModel()
|
||||||
|
val authService = currentUser()?.let { RemoteCommunicatorHolder.getProvider(it.providerCode) } ?.authService
|
||||||
syncPanelHolder.crossSyncSupported.set(authService?.crossSyncSupported() ?: true)
|
syncPanelHolder.crossSyncSupported.set(authService?.crossSyncSupported() ?: true)
|
||||||
val infoRow = row {
|
val infoRow = row {
|
||||||
@Suppress("DialogTitleCapitalization")
|
@Suppress("DialogTitleCapitalization")
|
||||||
@@ -188,22 +192,57 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
enableButtonAction()
|
enableButtonAction()
|
||||||
}
|
}
|
||||||
infoRow.visibleIf(enableCheckbox.selected.not())
|
infoRow.visibleIf(enableCheckbox.selected.not())
|
||||||
userDropDownLink = DropDownLink<UserProviderHolder?>(userProviderHolder) { link: DropDownLink<UserProviderHolder?>? -> showAccounts(link) }
|
|
||||||
cellDropDownLink = cell(userDropDownLink).onChangedContext { component, context ->
|
val listCellRenderer = listCellRenderer<UserProviderHolder>("") {
|
||||||
val event = context.event
|
val holder = value
|
||||||
if (event is ItemEvent && event.item == UserProviderHolder.addAccount) {
|
var icon2Apply = IconUtil.getEmptyIcon(false)
|
||||||
val syncTypeDialog = AddAccountDialog(configPanel)
|
when {
|
||||||
if (syncTypeDialog.showAndGet()) {
|
holder.userId == UserProviderHolder.LOGOUT_USER_ID -> {
|
||||||
val providerCode = syncTypeDialog.providerCode
|
separator { text = "" }
|
||||||
val provider = RemoteCommunicatorHolder.getProvider(providerCode) ?: return@onChangedContext
|
text(message("logout.link.text", holder.providerName)) {
|
||||||
component.selectedItem = null
|
attributes = SimpleTextAttributes.LINK_PLAIN_ATTRIBUTES.derive(
|
||||||
component.text = ""
|
SimpleTextAttributes.STYLE_PLAIN,
|
||||||
login(provider, syncConfigPanel)
|
JBUI.CurrentTheme.Link.Foreground.ENABLED,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
)
|
||||||
|
font = JBFont.medium()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
holder == UserProviderHolder.ADD_ACCOUNT -> {
|
||||||
|
icon(icon2Apply)
|
||||||
|
separator { text = "" }
|
||||||
|
text(holder.toString())
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
if (index == -1) {
|
||||||
|
RemoteCommunicatorHolder.getProvider(holder.providerCode)?.authService?.icon?.let {
|
||||||
|
icon2Apply = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (index == 0 || holder.providerCode != userAccountsList[index - 1].providerCode) {
|
||||||
|
separator { text = holder.providerName }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index >= 0 && holder == userComboBoxModel.selectedItem) {
|
||||||
|
icon2Apply = AllIcons.Actions.Checked
|
||||||
|
}
|
||||||
|
icon(icon2Apply)
|
||||||
|
text(holder.toString())
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
component.text = component.selectedItem.toString()
|
|
||||||
}
|
}
|
||||||
}.comment("", MAX_LINE_LENGTH_NO_WRAP)
|
}
|
||||||
|
|
||||||
|
cellUserComboBox = comboBox(userComboBoxModel, listCellRenderer)
|
||||||
|
.resizableColumn().align(AlignX.FILL)
|
||||||
|
.comment("", 50)
|
||||||
|
cellUserComboBox.whenItemSelectedFromUi { item ->
|
||||||
|
if (item != userProviderHolder) {
|
||||||
|
tryChangeAccount(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}.visibleIf(userAccountListIsNotEmpty)
|
}.visibleIf(userAccountListIsNotEmpty)
|
||||||
|
|
||||||
// settings to sync
|
// settings to sync
|
||||||
@@ -249,26 +288,28 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
wasUsedBefore.set(currentUser() != null)
|
wasUsedBefore.set(currentUser() != null)
|
||||||
hasMultipleProviders.set(RemoteCommunicatorHolder.getExternalProviders().isNotEmpty())
|
hasMultipleProviders.set(RemoteCommunicatorHolder.getExternalProviders().isNotEmpty())
|
||||||
enableCheckbox.isSelected = SettingsSyncSettings.getInstance().syncEnabled
|
enableCheckbox.isSelected = SettingsSyncSettings.getInstance().syncEnabled
|
||||||
if (currentUser() != null) {
|
userProviderHolder = if (currentUser() != null) {
|
||||||
userDropDownLink.selectedItem = userAccountsList.firstOrNull { it.userId == SettingsSyncLocalSettings.getInstance().userId}
|
userAccountsList.firstOrNull { it.userId == currentUserId() }
|
||||||
} else if (userAccountListIsNotEmpty.get()) {
|
} else if (userAccountListIsNotEmpty.get()) {
|
||||||
userDropDownLink.selectedItem = userAccountsList.firstOrNull { it != UserProviderHolder.addAccount }
|
userAccountsList.firstOrNull { it != UserProviderHolder.ADD_ACCOUNT }
|
||||||
} else {
|
} else {
|
||||||
userDropDownLink.selectedItem = null
|
null
|
||||||
}
|
}
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
syncStatusChanged()
|
syncStatusChanged()
|
||||||
}
|
}
|
||||||
.onIsModified {
|
.onIsModified {
|
||||||
enableCheckbox.isSelected != SettingsSyncSettings.getInstance().syncEnabled
|
enableCheckbox.isSelected != SettingsSyncSettings.getInstance().syncEnabled
|
||||||
|| syncConfigPanel.isModified()
|
|| syncConfigPanel.isModified()
|
||||||
|| (SettingsSyncLocalSettings.getInstance().userId != null && userDropDownLink.selectedItem?.userId != SettingsSyncLocalSettings.getInstance().userId)
|
|| (currentUserId() != null && selectedUser()?.userId != currentUserId())
|
||||||
}
|
}
|
||||||
.onApply {
|
.onApply {
|
||||||
|
val selectedUser = selectedUser()
|
||||||
with(SettingsSyncLocalSettings.getInstance()) {
|
with(SettingsSyncLocalSettings.getInstance()) {
|
||||||
userId = userDropDownLink.selectedItem?.userId
|
userId = selectedUser?.userId
|
||||||
providerCode = userDropDownLink.selectedItem?.providerCode
|
providerCode = selectedUser?.providerCode
|
||||||
}
|
}
|
||||||
cellDropDownLink.comment?.text = ""
|
cellUserComboBox.comment?.text = ""
|
||||||
if (enableCheckbox.isSelected) {
|
if (enableCheckbox.isSelected) {
|
||||||
syncConfigPanel.apply()
|
syncConfigPanel.apply()
|
||||||
}
|
}
|
||||||
@@ -349,7 +390,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
runWithModalProgressBlocking(ModalTaskOwner.component(configPanel), message("enable.sync.check.server.data.progress")) {
|
runWithModalProgressBlocking(ModalTaskOwner.component(configPanel), message("enable.sync.check.server.data.progress")) {
|
||||||
val (userId, userData, providerCode, providerName) = userDropDownLink.selectedItem ?: run {
|
val (userId, _, providerCode, providerName) = selectedUser() ?: run {
|
||||||
LOG.warn("No selected user")
|
LOG.warn("No selected user")
|
||||||
showErrorOnEDT(message("enable.dialog.error.no.user"))
|
showErrorOnEDT(message("enable.dialog.error.no.user"))
|
||||||
enableCheckbox.isSelected = false
|
enableCheckbox.isSelected = false
|
||||||
@@ -372,7 +413,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
syncConfigPanel.reset()
|
syncConfigPanel.reset()
|
||||||
triggerUpdateConfigurable()
|
triggerUpdateConfigurable()
|
||||||
}
|
}
|
||||||
cellDropDownLink.comment?.text = "<icon src='AllIcons.General.History'> " +
|
cellUserComboBox.comment?.text = "<icon src='AllIcons.General.History'> " +
|
||||||
message("sync.status.will.enable",
|
message("sync.status.will.enable",
|
||||||
CommonBundle.getApplyButtonText().replace(BundleBase.MNEMONIC_STRING, ""))
|
CommonBundle.getApplyButtonText().replace(BundleBase.MNEMONIC_STRING, ""))
|
||||||
} else {
|
} else {
|
||||||
@@ -384,7 +425,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
val syncDisableOption = showDisableSyncDialog()
|
val syncDisableOption = showDisableSyncDialog()
|
||||||
if (syncDisableOption != DisableSyncType.DONT_DISABLE) {
|
if (syncDisableOption != DisableSyncType.DONT_DISABLE) {
|
||||||
disableSyncOption.set(syncDisableOption)
|
disableSyncOption.set(syncDisableOption)
|
||||||
cellDropDownLink.comment?.text = message("sync.status.will.disable")
|
cellUserComboBox.comment?.text = message("sync.status.will.disable")
|
||||||
handleDisableSync()
|
handleDisableSync()
|
||||||
} else {
|
} else {
|
||||||
enableCheckbox.isSelected = true
|
enableCheckbox.isSelected = true
|
||||||
@@ -395,7 +436,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showDisableSyncDialog(): DisableSyncType {
|
private fun showDisableSyncDialog(): DisableSyncType {
|
||||||
val providerName = userDropDownLink.selectedItem?.providerName ?: ""
|
val providerName = selectedUser()?.providerName ?: ""
|
||||||
val intResult = if (SettingsSyncStatusTracker.getInstance().currentStatus is SettingsSyncStatusTracker.SyncStatus.ActionRequired) {
|
val intResult = if (SettingsSyncStatusTracker.getInstance().currentStatus is SettingsSyncStatusTracker.SyncStatus.ActionRequired) {
|
||||||
Messages.showDialog(
|
Messages.showDialog(
|
||||||
message("disable.dialog.text", providerName),
|
message("disable.dialog.text", providerName),
|
||||||
@@ -504,134 +545,121 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
syncTypeLabel.text = html.toString()
|
syncTypeLabel.text = html.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showAccounts(link: DropDownLink<UserProviderHolder?>?): JBPopup {
|
private fun tryChangeAccount(selectedValue: UserProviderHolder) {
|
||||||
val accounts = object : BaseListPopupStep<UserProviderHolder>() {
|
when {
|
||||||
private var stepSelectedValue: UserProviderHolder? = null
|
selectedValue == UserProviderHolder.ADD_ACCOUNT -> {
|
||||||
override fun onChosen(selectedValue: UserProviderHolder, finalChoice: Boolean): PopupStep<*>? {
|
if (SettingsSyncSettings.getInstance().syncEnabled && !disableCurrentSyncDialog()) {
|
||||||
stepSelectedValue = selectedValue
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
return FINAL_CHOICE
|
return
|
||||||
}
|
}
|
||||||
|
val syncTypeDialog = AddAccountDialog(configPanel)
|
||||||
override fun getTextFor(value: UserProviderHolder?): String {
|
if (syncTypeDialog.showAndGet()) {
|
||||||
return if (value == UserProviderHolder.addAccount) {
|
val providerCode = syncTypeDialog.providerCode
|
||||||
message("enable.sync.add.account")
|
val provider = RemoteCommunicatorHolder.getProvider(providerCode) ?: return
|
||||||
|
login(provider, syncConfigPanel)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value?.toString() ?: ""
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
selectedValue.userId == UserProviderHolder.LOGOUT_USER_ID -> {
|
||||||
override fun getSeparatorAbove(value: UserProviderHolder?): ListSeparator? {
|
val logoutFunction = userProviderHolder?.let { user ->
|
||||||
return value?.separatorString?.let { ListSeparator(it) }
|
val provider = RemoteCommunicatorHolder.getProvider(user.providerCode)
|
||||||
}
|
provider?.authService?.logoutFunction
|
||||||
|
|
||||||
override fun getFinalRunnable(): Runnable? {
|
|
||||||
if (stepSelectedValue != null) {
|
|
||||||
return Runnable { tryChangeAccount(stepSelectedValue!!) }
|
|
||||||
}
|
}
|
||||||
return null
|
if (logoutFunction != null) {
|
||||||
}
|
coroutineScope.launch(ModalityState.current().asContextElement()) {
|
||||||
|
withContext(Dispatchers.EDT) {
|
||||||
init {
|
logoutFunction(configPanel)
|
||||||
init(null, userAccountsList, emptyList())
|
configPanel.reset()
|
||||||
defaultOptionIndex = userAccountsList.indexOf(userDropDownLink.selectedItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val currentProviderCode = link?.selectedItem?.providerCode
|
|
||||||
|
|
||||||
val project = CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(configPanel))
|
|
||||||
val provider = currentProviderCode?.let { RemoteCommunicatorHolder.getProvider(it ) }
|
|
||||||
val logoutFunction = provider?.authService?.logoutFunction
|
|
||||||
val listPopup = object : ListPopupImpl(project, accounts) {
|
|
||||||
|
|
||||||
override fun setFooterComponent(c: JComponent?) {
|
|
||||||
val thePopup = this
|
|
||||||
if (logoutFunction == null) {
|
|
||||||
return super.setFooterComponent(c)
|
|
||||||
}
|
|
||||||
super.setFooterComponent(DslLabel(DslLabelType.LABEL).apply {
|
|
||||||
text = "<a>${message("logout.link.text", provider.authService.providerName ?: "")}</a>"
|
|
||||||
|
|
||||||
addHyperlinkListener {
|
|
||||||
if (it.eventType == HyperlinkEvent.EventType.ACTIVATED) {
|
|
||||||
thePopup.cancel()
|
|
||||||
coroutineScope.launch(ModalityState.current().asContextElement()) {
|
|
||||||
withContext(Dispatchers.EDT) {
|
|
||||||
logoutFunction(configPanel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreground = JBUI.CurrentTheme.Advertiser.foreground()
|
|
||||||
background = JBUI.CurrentTheme.Advertiser.background()
|
|
||||||
|
|
||||||
setOpaque(true)
|
|
||||||
setFont(RelativeFont.NORMAL.scale(JBUI.CurrentTheme.Advertiser.FONT_SIZE_OFFSET.get(), scale(11f)).derive(labelFont))
|
|
||||||
setBorder(JBUI.CurrentTheme.Advertiser.border())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (currentProviderCode != null && logoutFunction != null) {
|
|
||||||
listPopup.setAdText(message("logout.link.text", currentProviderCode)) // doesn't matter, will be changed
|
|
||||||
}
|
|
||||||
|
|
||||||
return listPopup
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun tryChangeAccount(selectedValue: UserProviderHolder) {
|
|
||||||
if (selectedValue == UserProviderHolder.addAccount) {
|
|
||||||
if (SettingsSyncSettings.getInstance().syncEnabled && !disableCurrentSyncDialog()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val syncTypeDialog = AddAccountDialog(configPanel)
|
|
||||||
if (syncTypeDialog.showAndGet()) {
|
|
||||||
val providerCode = syncTypeDialog.providerCode
|
|
||||||
val provider = RemoteCommunicatorHolder.getProvider(providerCode) ?: return
|
|
||||||
login(provider, syncConfigPanel)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val wasEnabled = SettingsSyncSettings.getInstance().syncEnabled
|
|
||||||
if (enableCheckbox.isSelected) {
|
|
||||||
if (wasEnabled) {
|
|
||||||
if (!disableCurrentSyncDialog()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
userDropDownLink.selectedItem = selectedValue
|
|
||||||
enableCheckbox.doClick()
|
|
||||||
} else {
|
} else {
|
||||||
userDropDownLink.selectedItem = selectedValue
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
enableButtonAction()
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
val wasEnabled = SettingsSyncSettings.getInstance().syncEnabled
|
||||||
|
if (enableCheckbox.isSelected) {
|
||||||
|
if (wasEnabled) {
|
||||||
|
if (!disableCurrentSyncDialog()) {
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder // setting old value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
enableCheckbox.doClick()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
enableButtonAction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
userProviderHolder = selectedValue
|
||||||
|
if (updateUserAccountLogout(selectedValue)) {
|
||||||
|
updateUserComboBoxModel()
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
userDropDownLink.selectedItem = selectedValue
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateUserAccountsList(): Boolean {
|
||||||
private fun updateUserAccountsList() {
|
val newList = arrayListOf<UserProviderHolder>()
|
||||||
userAccountsList.clear()
|
|
||||||
val providersList = RemoteCommunicatorHolder.getAvailableProviders()
|
val providersList = RemoteCommunicatorHolder.getAvailableProviders()
|
||||||
providersList.forEach { communicator ->
|
providersList.forEach { communicator ->
|
||||||
val authService = communicator.authService
|
val authService = communicator.authService
|
||||||
val providerName = authService.providerName
|
val providerName = authService.providerName
|
||||||
authService.getAvailableUserAccounts().forEachIndexed { idx, account ->
|
newList.addAll(authService.getAvailableUserAccounts().map { it.toUserProviderHolder(providerName) })
|
||||||
val separatorString = if (idx == 0)
|
|
||||||
providerName
|
|
||||||
else
|
|
||||||
null
|
|
||||||
userAccountsList.add(account.toUserProviderHolder(providerName, separatorString))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (hasMultipleProviders.get()) {
|
if (hasMultipleProviders.get()) {
|
||||||
userAccountsList.add(UserProviderHolder.addAccount)
|
newList.add(UserProviderHolder.ADD_ACCOUNT)
|
||||||
}
|
}
|
||||||
userAccountListIsNotEmpty.set(userAccountsList.any { it != UserProviderHolder.addAccount })
|
if (newList != userAccountsList) {
|
||||||
|
userAccountsList.clear()
|
||||||
|
userAccountsList.addAll(newList)
|
||||||
|
userAccountListIsNotEmpty.set(userAccountsList.any { it != UserProviderHolder.ADD_ACCOUNT })
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateUserAccountLogout(selectedUser: UserProviderHolder?): Boolean {
|
||||||
|
val newUserAccountsLogout = selectedUser?.providerCode?.let {
|
||||||
|
val provider = RemoteCommunicatorHolder.getProvider(it)
|
||||||
|
provider?.authService?.logoutFunction?.let {
|
||||||
|
UserProviderHolder.logout(provider.providerCode, provider.authService.providerName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (newUserAccountsLogout != userAccountsLogout) {
|
||||||
|
userAccountsLogout = newUserAccountsLogout
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateUserComboBoxModel() {
|
||||||
|
val selectedUser = selectedUser()
|
||||||
|
userComboBoxModel.update(userAccountsList + listOfNotNull(userAccountsLogout))
|
||||||
|
userComboBoxModel.selectedItem = selectedUser
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateCurrentUser() {
|
||||||
|
val currentUser = currentUser()
|
||||||
|
if (currentUser in userAccountsList) {
|
||||||
|
userProviderHolder = currentUser
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// logout from an active account could happen somewhere else, should switch users manually
|
||||||
|
val newCurrentUser = userAccountsList.firstOrNull { it != UserProviderHolder.ADD_ACCOUNT }
|
||||||
|
if (SettingsSyncSettings.getInstance().syncEnabled) {
|
||||||
|
handleDisableSync()
|
||||||
|
}
|
||||||
|
with(SettingsSyncLocalSettings.getInstance()) {
|
||||||
|
userId = newCurrentUser?.userId
|
||||||
|
providerCode = newCurrentUser?.providerCode
|
||||||
|
}
|
||||||
|
userProviderHolder = newCurrentUser
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun login(
|
private fun login(
|
||||||
provider: SettingsSyncCommunicatorProvider,
|
provider: SettingsSyncCommunicatorProvider,
|
||||||
syncConfigPanel: DialogPanel,
|
syncConfigPanel: DialogPanel,
|
||||||
@@ -646,17 +674,25 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
val remoteCommunicator = RemoteCommunicatorHolder.createRemoteCommunicator(provider, userData.id, loginDisposable) ?: return@withContext
|
val remoteCommunicator = RemoteCommunicatorHolder.createRemoteCommunicator(provider, userData.id, loginDisposable) ?: return@withContext
|
||||||
if (checkServerState(syncPanelHolder, remoteCommunicator, provider.authService.crossSyncSupported())) {
|
if (checkServerState(syncPanelHolder, remoteCommunicator, provider.authService.crossSyncSupported())) {
|
||||||
SettingsSyncEvents.getInstance().fireLoginStateChanged()
|
SettingsSyncEvents.getInstance().fireLoginStateChanged()
|
||||||
userDropDownLink.selectedItem = UserProviderHolder(userData.id, userData, provider.authService.providerCode,
|
val newHolder = UserProviderHolder(userData.id, userData, provider.authService.providerCode, provider.authService.providerName, null)
|
||||||
provider.authService.providerName, null)
|
userProviderHolder = newHolder
|
||||||
|
userComboBoxModel.selectedItem = newHolder
|
||||||
|
updateUserAccountLogout(newHolder)
|
||||||
|
updateUserComboBoxModel()
|
||||||
|
|
||||||
enableCheckbox.isSelected = true
|
enableCheckbox.isSelected = true
|
||||||
wasUsedBefore.set(true)
|
wasUsedBefore.set(true)
|
||||||
syncConfigPanel.reset()
|
syncConfigPanel.reset()
|
||||||
triggerUpdateConfigurable()
|
triggerUpdateConfigurable()
|
||||||
|
} else {
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
|
updateUserComboBoxModel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
LOG.info("Received empty user data from login")
|
LOG.info("Received empty user data from login")
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (ex: CancellationException) {
|
catch (ex: CancellationException) {
|
||||||
@@ -665,6 +701,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
}
|
}
|
||||||
catch (ex: Throwable) {
|
catch (ex: Throwable) {
|
||||||
LOG.warn("Error during login", ex)
|
LOG.warn("Error during login", ex)
|
||||||
|
userComboBoxModel.selectedItem = userProviderHolder
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
Disposer.dispose(loginDisposable)
|
Disposer.dispose(loginDisposable)
|
||||||
@@ -677,16 +714,19 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
UserProviderHolder(id, this, providerCode, providerName, separatorString)
|
UserProviderHolder(id, this, providerCode, providerName, separatorString)
|
||||||
|
|
||||||
override fun syncStatusChanged() {
|
override fun syncStatusChanged() {
|
||||||
if (!::cellDropDownLink.isInitialized)
|
if (!::cellUserComboBox.isInitialized)
|
||||||
return
|
return
|
||||||
updateUserAccountsList()
|
if (updateUserAccountsList()) {
|
||||||
|
if (updateUserAccountLogout(selectedUser())) {
|
||||||
|
updateUserComboBoxModel()
|
||||||
|
}
|
||||||
|
}
|
||||||
refreshActionRequired()
|
refreshActionRequired()
|
||||||
if (!enableCheckbox.isSelected) {
|
if (!enableCheckbox.isSelected) {
|
||||||
if (lastRemoveRemoteDataError != null) {
|
if (lastRemoveRemoteDataError != null) {
|
||||||
cellDropDownLink.comment?.text = "<icon src='AllIcons.General.Error'> " +
|
cellUserComboBox.comment?.text = "<icon src='AllIcons.General.Error'> " + message("disable.remove.data.failure", lastRemoveRemoteDataError!!)
|
||||||
message("disable.remove.data.failure", lastRemoveRemoteDataError!!)
|
|
||||||
} else {
|
} else {
|
||||||
cellDropDownLink.comment?.text = ""
|
cellUserComboBox.comment?.text = ""
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -695,19 +735,18 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
if (currentStatus == SettingsSyncStatusTracker.SyncStatus.Success) {
|
if (currentStatus == SettingsSyncStatusTracker.SyncStatus.Success) {
|
||||||
val lastSyncTime = SettingsSyncStatusTracker.getInstance().getLastSyncTime()
|
val lastSyncTime = SettingsSyncStatusTracker.getInstance().getLastSyncTime()
|
||||||
if (lastSyncTime > 0) {
|
if (lastSyncTime > 0) {
|
||||||
cellDropDownLink.comment?.text = "<icon src='AllIcons.General.GreenCheckmark'> " + message("sync.status.last.sync.message", DateFormatUtil.formatPrettyDateTime(lastSyncTime))
|
cellUserComboBox.comment?.text = "<icon src='AllIcons.General.GreenCheckmark'> " + message("sync.status.last.sync.message", DateFormatUtil.formatPrettyDateTime(lastSyncTime))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cellDropDownLink.comment?.text = message("sync.status.enabled")
|
cellUserComboBox.comment?.text = message("sync.status.enabled")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (currentStatus is SettingsSyncStatusTracker.SyncStatus.Error) {
|
else if (currentStatus is SettingsSyncStatusTracker.SyncStatus.Error) {
|
||||||
cellDropDownLink.comment?.text = message("sync.status.failed", currentStatus.errorMessage)
|
cellUserComboBox.comment?.text = message("sync.status.failed", currentStatus.errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
//statusLabel.icon = icons.SettingsSyncIcons.StatusNotRun
|
cellUserComboBox.comment?.text = ""
|
||||||
cellDropDownLink.comment?.text = ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,12 +763,12 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
}
|
}
|
||||||
actionRequiredLabel.text = userActionRequired.message
|
actionRequiredLabel.text = userActionRequired.message
|
||||||
actionRequiredButton.text = userActionRequired.actionTitle
|
actionRequiredButton.text = userActionRequired.actionTitle
|
||||||
cellDropDownLink.comment?.text = message("sync.status.action.required.comment",
|
cellUserComboBox.comment?.text = message("sync.status.action.required.comment",
|
||||||
userActionRequired.actionTitle,
|
userActionRequired.actionTitle,
|
||||||
userActionRequired.actionDescription ?: userActionRequired.message)
|
userActionRequired.actionDescription ?: userActionRequired.message)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
cellDropDownLink.comment?.text = ""
|
cellUserComboBox.comment?.text = ""
|
||||||
actionRequiredAction = null
|
actionRequiredAction = null
|
||||||
actionRequiredLabel.text = ""
|
actionRequiredLabel.text = ""
|
||||||
actionRequiredButton.text = ""
|
actionRequiredButton.text = ""
|
||||||
@@ -739,7 +778,7 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
private fun getPendingUserAction(): PendingUserAction? {
|
private fun getPendingUserAction(): PendingUserAction? {
|
||||||
if (!enableCheckbox.isSelected)
|
if (!enableCheckbox.isSelected)
|
||||||
return null
|
return null
|
||||||
return userDropDownLink.selectedItem?.let {
|
return selectedUser()?.let {
|
||||||
RemoteCommunicatorHolder.getProvider(it.providerCode)?.authService?.getPendingUserAction(it.userId)
|
RemoteCommunicatorHolder.getProvider(it.providerCode)?.authService?.getPendingUserAction(it.userId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,10 +854,14 @@ internal class SettingsSyncConfigurable(private val coroutineScope: CoroutineSco
|
|||||||
val providerName: String,
|
val providerName: String,
|
||||||
val separatorString: String?, // separator value, set only for the first account in the list
|
val separatorString: String?, // separator value, set only for the first account in the list
|
||||||
) {
|
) {
|
||||||
companion object{
|
companion object {
|
||||||
val addAccount = UserProviderHolder(
|
val ADD_ACCOUNT = UserProviderHolder(
|
||||||
"<ADDACCOUNT>", SettingsSyncUserData("<ADDACCOUNT>", "", null, null), "",
|
"<ADD_ACCOUNT>", SettingsSyncUserData("<ADD_ACCOUNT>", "", null, null, message("enable.sync.add.account")), "",
|
||||||
"", "")
|
"", "")
|
||||||
|
const val LOGOUT_USER_ID = "<LOGOUT>"
|
||||||
|
fun logout(providerCode: String, providerName: String) = UserProviderHolder(
|
||||||
|
LOGOUT_USER_ID, SettingsSyncUserData(LOGOUT_USER_ID, providerCode, null, null, LOGOUT_USER_ID), providerCode,
|
||||||
|
providerName, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
|
|||||||
Reference in New Issue
Block a user