mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-82344 Implement main promo components and project activities
GitOrigin-RevId: 5fec5e7f2b88743a97d10b7f0d27f9173c8424fd
This commit is contained in:
committed by
intellij-monorepo-bot
parent
2c3577596c
commit
0ffc947c7f
@@ -123,7 +123,7 @@ class GotItTooltip @ApiStatus.Internal constructor(@NonNls val id: String,
|
||||
/**
|
||||
* Add an optional image above the header or description
|
||||
*/
|
||||
private fun withImage(image: Icon, withBorder: Boolean = true): GotItTooltip {
|
||||
fun withImage(image: Icon, withBorder: Boolean = true): GotItTooltip {
|
||||
gotItBuilder.withImage(image, withBorder)
|
||||
return this
|
||||
}
|
||||
|
||||
+4
-1
@@ -82,7 +82,10 @@
|
||||
bundle="messages.PyCharmCommunityCustomizationBundle"
|
||||
key="promo.configurable.jupyter"/>
|
||||
|
||||
|
||||
<startPagePromoter
|
||||
implementation="com.intellij.pycharm.community.ide.impl.promotion.communityToUnified.PyCommunityToUnifiedWelcomeScreenBanner"/>
|
||||
<postStartupActivity
|
||||
implementation="com.intellij.pycharm.community.ide.impl.promotion.communityToUnified.PyCommunityToUnifiedShowPromoActivity"/>
|
||||
<!--TODO delete later-->
|
||||
<registryKey key="py.promo.use.test.update"
|
||||
defaultValue="false"
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.openapi.components.Service
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import kotlinx.coroutines.*
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import kotlin.coroutines.cancellation.CancellationException
|
||||
|
||||
@Service(Service.Level.APP)
|
||||
@ApiStatus.Internal
|
||||
class PyCharmCommunityToUnifiedScheduleService(val serviceScope: CoroutineScope) {
|
||||
companion object {
|
||||
val LOG: Logger = logger<PyCharmCommunityToUnifiedScheduleService>()
|
||||
fun getInstance(): PyCharmCommunityToUnifiedScheduleService = service<PyCharmCommunityToUnifiedScheduleService>()
|
||||
}
|
||||
|
||||
private var remindLaterJob: Job? = null
|
||||
|
||||
fun scheduleFallbackModal() {
|
||||
val promoService = service<PyCommunityToUnifiedPromoService>()
|
||||
// cancel previous scheduled task if any
|
||||
remindLaterJob?.cancel()
|
||||
val delayMs = promoService.getPromoIntervalMillis()
|
||||
remindLaterJob = serviceScope.launch(Dispatchers.Default) {
|
||||
try {
|
||||
delay(delayMs)
|
||||
// Only proceed if conditions still require showing modal
|
||||
if (!promoService.shouldShowModal()) return@launch
|
||||
val project = ProjectManager.getInstance().openProjects.firstOrNull() ?: run {
|
||||
LOG.info("Skipping promo modal fallback: no open projects")
|
||||
return@launch
|
||||
}
|
||||
PyCommunityToUnifiedShowPromoActivity.showModalPromo(project)
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
if (t is CancellationException) throw t
|
||||
LOG.warn("Error in promo modal fallback task", t)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.ui.DialogWrapper
|
||||
import com.intellij.ui.PopupBorder
|
||||
import com.intellij.ui.WindowRoundedCornersManager
|
||||
import com.intellij.ui.components.JBLabel
|
||||
import com.intellij.ui.components.panels.BackgroundRoundedPanel
|
||||
import com.intellij.ui.dsl.builder.EmptySpacingConfiguration
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
|
||||
import com.intellij.ui.dsl.gridLayout.UnscaledGapsY
|
||||
import com.intellij.util.ui.JBFont
|
||||
import com.intellij.util.ui.JBUI
|
||||
import java.awt.BorderLayout
|
||||
import java.awt.Dimension
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.JRootPane
|
||||
import javax.swing.border.Border
|
||||
|
||||
internal class PyCommunityToUnifiedPromoDialog(project: Project?) :
|
||||
DialogWrapper(project, null, false,
|
||||
IdeModalityType.IDE, true, false) {
|
||||
|
||||
private val imageIcon = PyPromoSharedComponents.popUpImg
|
||||
|
||||
override fun createContentPaneBorder(): Border {
|
||||
return JBUI.Borders.empty()
|
||||
}
|
||||
|
||||
override fun getStyle(): DialogStyle {
|
||||
return super.getStyle()
|
||||
}
|
||||
|
||||
init {
|
||||
setUndecorated(true)
|
||||
rootPane.windowDecorationStyle = JRootPane.NONE
|
||||
rootPane.border = PopupBorder.Factory.create(true, true)
|
||||
WindowRoundedCornersManager.configure(this)
|
||||
init()
|
||||
}
|
||||
|
||||
override fun createSouthPanel(): JComponent? {
|
||||
return panel {
|
||||
row {
|
||||
button(PyPromoSharedComponents.updateNow) {
|
||||
close(OK_EXIT_CODE)
|
||||
}.focused()
|
||||
.applyToComponent {
|
||||
putClientProperty("gotItButton", true)
|
||||
putClientProperty(DarculaButtonUI.DEFAULT_STYLE_KEY, true)
|
||||
this@PyCommunityToUnifiedPromoDialog.rootPane.defaultButton = this
|
||||
}.customize(customGaps = UnscaledGaps(right = 10))
|
||||
link(PyPromoSharedComponents.skip) {
|
||||
close(CANCEL_EXIT_CODE)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
setSize(imageIcon.iconWidth, it.preferredSize.height)
|
||||
it.border = JBUI.Borders.empty(0, 28, 28, 28)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun createCenterPanel(): JComponent {
|
||||
val mainPanel = BackgroundRoundedPanel(16, BorderLayout())
|
||||
val imagePanel = createImagePanel()
|
||||
val infoPanel = createInfoPanel()
|
||||
mainPanel.add(imagePanel, BorderLayout.NORTH)
|
||||
mainPanel.add(infoPanel, BorderLayout.SOUTH)
|
||||
mainPanel.preferredSize = Dimension(imageIcon.iconWidth, 200)
|
||||
pack()
|
||||
return mainPanel
|
||||
}
|
||||
|
||||
private fun createImagePanel(): JPanel {
|
||||
val imagePanel = JPanel(BorderLayout())
|
||||
val imageLabel = JBLabel(imageIcon)
|
||||
imagePanel.add(imageLabel, BorderLayout.CENTER)
|
||||
return imagePanel
|
||||
}
|
||||
|
||||
private fun createInfoPanel(): JPanel {
|
||||
return panel {
|
||||
customizeSpacingConfiguration(EmptySpacingConfiguration()) {
|
||||
row {
|
||||
label(PyPromoSharedComponents.headerTitle)
|
||||
.applyToComponent {
|
||||
font = JBFont.h2().asBold()
|
||||
}
|
||||
}
|
||||
row {
|
||||
text(PyPromoSharedComponents.mainText, maxLineLength = 40)
|
||||
.applyToComponent {
|
||||
foreground = PyPromoSharedComponents.infoFontColor
|
||||
}
|
||||
}.customize(customRowGaps = UnscaledGapsY(top = 4))
|
||||
row {
|
||||
browserLink(PyPromoSharedComponents.learnMore, PyPromoSharedComponents.LEARN_MORE_URL)
|
||||
}.customize(customRowGaps = UnscaledGapsY(top = 4, bottom = 12))
|
||||
}
|
||||
}.also {
|
||||
setSize(imageIcon.iconWidth, it.preferredSize.height)
|
||||
it.border = JBUI.Borders.empty(28, 28, 0, 28)
|
||||
}
|
||||
}
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.startup.ProjectActivity
|
||||
import com.intellij.openapi.updateSettings.impl.PlatformUpdateDialog
|
||||
import com.intellij.openapi.updateSettings.impl.PlatformUpdates
|
||||
import com.intellij.openapi.updateSettings.impl.UpdateSettings
|
||||
import com.intellij.util.PlatformUtils
|
||||
import com.intellij.util.application
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
class PyCommunityToUnifiedShowPromoActivity : ProjectActivity {
|
||||
|
||||
override suspend fun execute(project: Project) {
|
||||
showPromoIfNeeded(project)
|
||||
}
|
||||
|
||||
suspend fun showPromoIfNeeded(project: Project) {
|
||||
if (project.isDisposed || application.isHeadlessEnvironment || !PlatformUtils.isPyCharmCommunity()) return
|
||||
|
||||
val promoService = service<PyCommunityToUnifiedPromoService>()
|
||||
val update = promoService.getAvailableUpdate()
|
||||
if (update == null) return
|
||||
|
||||
if (promoService.shouldShowTooltip()) {
|
||||
showTooltip(project)
|
||||
}
|
||||
else if (promoService.shouldShowModal()) {
|
||||
showModalPromo(project)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
val LOG: Logger = logger<PyCommunityToUnifiedShowPromoActivity>()
|
||||
|
||||
suspend fun showTooltip(project: Project) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
PyCommunityToUnifiedTooltip.showTooltip(project)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun showModalPromo(project: Project) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
val result = PyCommunityToUnifiedPromoDialog(project).showAndGet()
|
||||
if (!result) {
|
||||
service<PyCommunityToUnifiedPromoService>().onRemindMeLaterClicked()
|
||||
PyCharmCommunityToUnifiedScheduleService.getInstance().scheduleFallbackModal()
|
||||
}
|
||||
else {
|
||||
launchUpdateDialog(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun launchUpdateDialog(project: Project?) {
|
||||
val promoService = service<PyCommunityToUnifiedPromoService>()
|
||||
promoService.serviceScope.launch {
|
||||
val update = promoService.getAvailableUpdate()
|
||||
if (update != null) {
|
||||
showModalUpdateDialog(project, update)
|
||||
}
|
||||
else {
|
||||
LOG.warn("Update dialog was launched but no update was found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun showModalUpdateDialog(project: Project?, update: PlatformUpdates.Loaded) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
val result = PlatformUpdateDialog(project, update, true, emptyList(), emptyList()).showAndGet()
|
||||
val promoService = service<PyCommunityToUnifiedPromoService>()
|
||||
if (!result) {
|
||||
val buildNum = update.newBuild.number.asStringWithoutProductCode()
|
||||
// ignore this update was clicked
|
||||
if (UpdateSettings.getInstance().ignoredBuildNumbers.contains(buildNum)) {
|
||||
LOG.info("Update declined for: $buildNum")
|
||||
promoService.setUpdateDeclined()
|
||||
}
|
||||
else {
|
||||
LOG.info("Remind me later clicked for: $buildNum")
|
||||
promoService.onRemindMeLaterClicked()
|
||||
PyCharmCommunityToUnifiedScheduleService.getInstance().scheduleFallbackModal()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.openapi.actionSystem.ActionManager
|
||||
import com.intellij.openapi.actionSystem.AnAction
|
||||
import com.intellij.openapi.actionSystem.impl.ActionButton
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.wm.WindowManager
|
||||
import com.intellij.ui.GotItTooltip
|
||||
import com.intellij.util.IconUtil
|
||||
import com.intellij.util.ui.UIUtil
|
||||
import org.jetbrains.annotations.Nls
|
||||
|
||||
object PyCommunityToUnifiedTooltip {
|
||||
|
||||
private const val TOOLTIP_ID: String = "pycharm.community.to.unified.tooltip.id"
|
||||
|
||||
fun showTooltip(project: Project) {
|
||||
UIUtil.invokeLaterIfNeeded {
|
||||
val frame = WindowManager.getInstance().getIdeFrame(project) ?: return@invokeLaterIfNeeded
|
||||
val root = frame.component
|
||||
|
||||
val actionId = "SettingsEntryPoint"
|
||||
val targetAction: AnAction? = ActionManager.getInstance().getAction(actionId)
|
||||
if (targetAction == null) return@invokeLaterIfNeeded
|
||||
|
||||
val settingsButton: ActionButton? = UIUtil.uiTraverser(root)
|
||||
.filter(ActionButton::class.java)
|
||||
.firstOrNull { it.action == targetAction }
|
||||
|
||||
|
||||
if (settingsButton != null) {
|
||||
val tooltip = constructToolTip(project)
|
||||
// TODO won't show properly in the corner :(
|
||||
tooltip.show(settingsButton, GotItTooltip.BOTTOM_LEFT)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun constructToolTip(project: Project): GotItTooltip {
|
||||
val image = IconUtil.scale(PyPromoSharedComponents.popUpImg, null, 0.7f)
|
||||
fun @Nls String.h3(): String = "<html><b><span style='font-size:1.17em'>$this</span></b></html>"
|
||||
|
||||
return GotItTooltip(TOOLTIP_ID, PyPromoSharedComponents.mainText)
|
||||
.withImage(image)
|
||||
.withHeader(PyPromoSharedComponents.headerTitle.h3())
|
||||
.withButtonLabel(PyPromoSharedComponents.updateNow)
|
||||
.withLink(PyPromoSharedComponents.learnMore) {
|
||||
PyPromoSharedComponents.learnMoreBrowserAction.invoke()
|
||||
}
|
||||
.withSecondaryButton(PyPromoSharedComponents.skip) {
|
||||
PyCommunityToUnifiedPromoService.getInstance().onRemindMeLaterClicked()
|
||||
PyCharmCommunityToUnifiedScheduleService.getInstance().scheduleFallbackModal()
|
||||
}
|
||||
.withGotItButtonAction {
|
||||
PyCommunityToUnifiedShowPromoActivity.launchUpdateDialog(project)
|
||||
}
|
||||
.withShowCount(Int.MAX_VALUE)
|
||||
.withFocus()
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.ide.ui.laf.darcula.ui.DarculaButtonUI
|
||||
import com.intellij.openapi.application.EDT
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.wm.BannerStartPagePromoter
|
||||
import com.intellij.openapi.wm.StartPagePromoter
|
||||
import com.intellij.pycharm.community.ide.impl.promotion.icons.PycharmCommunityIdeImplPromotionIcons
|
||||
import com.intellij.ui.components.panels.BackgroundRoundedPanel
|
||||
import com.intellij.ui.components.panels.Wrapper
|
||||
import com.intellij.ui.dsl.builder.EmptySpacingConfiguration
|
||||
import com.intellij.ui.dsl.builder.TopGap
|
||||
import com.intellij.ui.dsl.builder.panel
|
||||
import com.intellij.ui.dsl.gridLayout.UnscaledGaps
|
||||
import com.intellij.ui.dsl.gridLayout.UnscaledGapsY
|
||||
import com.intellij.util.IconUtil
|
||||
import com.intellij.util.PlatformUtils
|
||||
import com.intellij.util.ui.JBFont
|
||||
import com.intellij.util.ui.JBUI
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import org.jetbrains.annotations.Nls
|
||||
import java.awt.Graphics
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.geom.RoundRectangle2D
|
||||
import javax.swing.BoxLayout
|
||||
import javax.swing.Icon
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import kotlin.math.min
|
||||
|
||||
@ApiStatus.Internal
|
||||
internal class PyCommunityToUnifiedWelcomeScreenBanner : BannerStartPagePromoter() {
|
||||
override val headerLabel: @Nls String = ""
|
||||
override val actionLabel: @Nls String = ""
|
||||
override val description: @Nls String = ""
|
||||
override val promoImage: Icon = PycharmCommunityIdeImplPromotionIcons.Backgrounds.Promotion_bg
|
||||
|
||||
private val mainBannerPanel = createMainPanel()
|
||||
|
||||
val container: Wrapper = Wrapper(mainBannerPanel).apply { isVisible = false }
|
||||
|
||||
override fun getPromotion(isEmptyState: Boolean): JComponent {
|
||||
val service = service<PyCommunityToUnifiedPromoService>()
|
||||
service.serviceScope.launch {
|
||||
val shouldShowBanner = service.shouldShowWelcomeScreenBanner()
|
||||
if (shouldShowBanner) {
|
||||
withContext(Dispatchers.EDT) {
|
||||
container.setContent(mainBannerPanel)
|
||||
container.isVisible = true
|
||||
container.revalidate()
|
||||
container.repaint()
|
||||
}
|
||||
}
|
||||
}
|
||||
return container
|
||||
}
|
||||
|
||||
override fun runAction() {}
|
||||
|
||||
override fun canCreatePromo(isEmptyState: Boolean): Boolean {
|
||||
return PlatformUtils.isPyCharmCommunity()
|
||||
}
|
||||
|
||||
override fun getPriorityLevel(): Int = StartPagePromoter.PRIORITY_LEVEL_HIGH
|
||||
|
||||
private fun createMainPanel(): JPanel {
|
||||
val panel = panel {
|
||||
customizeSpacingConfiguration(EmptySpacingConfiguration()) {
|
||||
row {
|
||||
label(PyPromoSharedComponents.headerTitle)
|
||||
.applyToComponent {
|
||||
font = JBFont.h3().asBold()
|
||||
}
|
||||
}.customize(customRowGaps = UnscaledGapsY(top = 12))
|
||||
row {
|
||||
text(PyPromoSharedComponents.mainText)
|
||||
.applyToComponent {
|
||||
foreground = PyPromoSharedComponents.infoFontColor
|
||||
}
|
||||
}.customize(customRowGaps = UnscaledGapsY(top = 4, bottom = 8))
|
||||
}
|
||||
row {
|
||||
button(PyPromoSharedComponents.updateNow) {
|
||||
PyCommunityToUnifiedShowPromoActivity.launchUpdateDialog(null)
|
||||
}.applyToComponent { putClientProperty(DarculaButtonUI.DEFAULT_STYLE_KEY, true) }
|
||||
.focused()
|
||||
.customize(customGaps = UnscaledGaps(right = 10))
|
||||
browserLink(PyPromoSharedComponents.learnMore, PyPromoSharedComponents.LEARN_MORE_URL)
|
||||
}.topGap(TopGap.NONE)
|
||||
}.apply {
|
||||
isOpaque = false
|
||||
border = JBUI.Borders.empty(0, 12, 16, 0)
|
||||
}
|
||||
return wrapIntoSvgBackgroundPanel(panel, JBUI.scale(16), promoImage)
|
||||
}
|
||||
|
||||
private fun wrapIntoSvgBackgroundPanel(panel: JPanel, arc: Int, bgImage: Icon): JPanel {
|
||||
val svgPanel = SvgBackgroundRightAnchoredPanel(arc, bgImage).apply {
|
||||
layout = BoxLayout(this, BoxLayout.X_AXIS)
|
||||
}
|
||||
svgPanel.add(panel)
|
||||
return svgPanel
|
||||
}
|
||||
|
||||
private class SvgBackgroundRightAnchoredPanel(
|
||||
private val arc: Int,
|
||||
private val bgImage: Icon,
|
||||
) : BackgroundRoundedPanel(arc) {
|
||||
|
||||
override fun paintComponent(g: Graphics) {
|
||||
super.paintComponent(g)
|
||||
if (width <= 0 || height <= 0) return
|
||||
|
||||
val iw = bgImage.iconWidth
|
||||
val ih = bgImage.iconHeight
|
||||
if (iw <= 0 || ih <= 0) return
|
||||
|
||||
val g2 = g.create() as Graphics2D
|
||||
try {
|
||||
g2.clip(RoundRectangle2D.Float(0f, 0f, width.toFloat(), height.toFloat(), arc.toFloat(), arc.toFloat()))
|
||||
val sx = width.toFloat() / iw
|
||||
val sy = height.toFloat() / ih
|
||||
val scale = min(sx, sy)
|
||||
|
||||
val scaled = IconUtil.scale(bgImage, this, scale)
|
||||
// Right-anchored (no padding)
|
||||
val x = width - scaled.iconWidth
|
||||
val y = 0
|
||||
scaled.paintIcon(this, g2, x, y)
|
||||
}
|
||||
finally {
|
||||
g2.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.pycharm.community.ide.impl.promotion.communityToUnified
|
||||
|
||||
import com.intellij.ide.BrowserUtil
|
||||
import com.intellij.pycharm.community.ide.impl.PyCharmCommunityCustomizationBundle
|
||||
import com.intellij.pycharm.community.ide.impl.promotion.icons.PycharmCommunityIdeImplPromotionIcons
|
||||
import com.intellij.ui.JBColor
|
||||
import java.awt.Color
|
||||
|
||||
internal object PyPromoSharedComponents {
|
||||
|
||||
val popUpImg = PycharmCommunityIdeImplPromotionIcons.Images.Popup_img
|
||||
val infoFontColor = JBColor(Color.decode("#6C707E"), Color.decode("#A8ADBD"))
|
||||
|
||||
// URLs used by promo-related messages
|
||||
const val LEARN_MORE_URL: String = "https://blog.jetbrains.com/pycharm/2025/04/unified-pycharm/"
|
||||
|
||||
// Actions
|
||||
val learnMoreBrowserAction = { BrowserUtil.browse(LEARN_MORE_URL) }
|
||||
|
||||
// Localized strings from PyCharmCommunityCustomizationBundle
|
||||
val mainText = PyCharmCommunityCustomizationBundle.message("promotion.update.to.unified.info.text")
|
||||
val learnMore = PyCharmCommunityCustomizationBundle.message("promotion.update.to.unified.learn.more.hyper.link")
|
||||
val updateNow = PyCharmCommunityCustomizationBundle.message("promotion.update.to.unified.update.now.button.label")
|
||||
val skip = PyCharmCommunityCustomizationBundle.message("promotion.update.to.unified.skip.button.label")
|
||||
val headerTitle = PyCharmCommunityCustomizationBundle.message("promotion.update.to.unified.banner.header.title")
|
||||
}
|
||||
Reference in New Issue
Block a user