Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,14 @@ Every donation, no matter the size, makes a difference and is deeply appreciated

## Changelog

### Version 1.9.4

1. Adding repair using AI(You can disable it in settings)

### Version 1.9.3

1. Improved the Analytics by adding session
2. Imorived dart code generation
2. Improved dart code generation
3. Tracking JSON when repair failed(This will be removed in next versions)

### Version 1.9.2
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pluginGroup=com.godwin.jsonparser
pluginName=Json Parser
# SemVer format -> https://semver.org
pluginVersion=1.9.3
pluginVersion=1.9.4
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
pluginSinceBuild=241
pluginUntilBuild=261.*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ class JsonPersistence : PersistentStateComponent<JsonPersistence> {
var starClicked: Int = 0
var analyticsEnabled: Boolean = true
var analyticsErrorJsonEnabled: Boolean = true
var repairUsingAi: Boolean = true

override fun getState(): JsonPersistence {
return this
}
Expand Down
82 changes: 61 additions & 21 deletions src/main/kotlin/com/godwin/jsonparser/ui/ParserWidget.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.godwin.jsonparser.generator.common.ui.*
import com.godwin.jsonparser.generator.common.util.FileGenerationUtil
import com.godwin.jsonparser.rx.Publisher
import com.godwin.jsonparser.rx.Subscriber
import com.godwin.jsonparser.ui.components.CircularProgress
import com.godwin.jsonparser.ui.dialog.OptionDialog
import com.godwin.jsonparser.util.JsonDownloader
import com.godwin.jsonparser.util.JsonUtils
Expand Down Expand Up @@ -44,6 +45,7 @@ class ParserWidget(
private val inputEditor: Editor = createEditor()
private val bodyWidget = ParserBodyWidget(project)
private var repairButton: JButton? = null
private var repairLoadingIndicator: CircularProgress? = null
private var generateCodeButton: JButton? = null
private var jsonException: Exception? = null
val container: JPanel = jBorderLayout {
Expand Down Expand Up @@ -80,6 +82,17 @@ class ParserWidget(
addActionListener { handleRepair() }
}
add(repairButton)
repairLoadingIndicator = CircularProgress().apply {
isVisible = false
preferredSize = java.awt.Dimension(18, 18)
toolTipText = "Repairing JSON..."
}
add(repairLoadingIndicator)
fillSpace()
jButton("Options", { handleOptions() })
}
jHorizontalLinearLayout {
jButton("Support ❤️", { handleDonate() })
fillSpace()
if (isAndroidStudioOrIntelliJ()) {
generateCodeButton = JButton("Generate Code").apply {
Expand All @@ -88,11 +101,6 @@ class ParserWidget(
}
add(generateCodeButton)
}
jButton("Options", { handleOptions() })
}
jHorizontalLinearLayout {
jButton("Support ❤️", { handleDonate() })
fillSpace()
}
}
}
Expand Down Expand Up @@ -165,7 +173,6 @@ class ParserWidget(
val jsonString = JsonUtils.cleanUpJsonString(inputEditor.document.text)
try {
showBody(jsonString)
showHideGenerateCodeButton(true)
NotificationUtil.showDonateNotification()
} catch (_: Exception) {
showHideGenerateCodeButton(false)
Expand Down Expand Up @@ -225,28 +232,52 @@ class ParserWidget(
showHideGenerateCodeButton(false)
AnalyticsService.track(AnalyticsConstant.PARSE_FAILED)
})
showHideGenerateCodeButton(true)
bodyWidget.showRaw(jsonString)
bodyWidget.showTree(jsonString)
}

private fun handleRepair() {
AnalyticsService.track(AnalyticsConstant.ACTION_REPAIR)
val input = inputEditor.document.text
try {
val repairedJson = JsonRepairEngine.repair(project, input)

showHideRepairButton(false)
// showDiff(input, repairedJson)
if (repairedJson == null) {
AnalyticsService.track(AnalyticsConstant.REPAIR_FAILED, jsonData = input)
NotificationUtil.showJsonRepairFailed()
return

setRepairLoading(true)

JsonRepairEngine.repair(input).thenAccept { repairedJson ->
SwingUtilities.invokeLater {
setRepairLoading(false)
if (repairedJson == null) {
AnalyticsService.track(AnalyticsConstant.REPAIR_FAILED, jsonData = input)
NotificationUtil.showJsonRepairFailed()
return@invokeLater
}
showHideRepairButton(false)
showMergeRepair(input, repairedJson)
handleParse()
}
}.exceptionally { e ->
SwingUtilities.invokeLater {
setRepairLoading(false)
Messages.showErrorDialog(project, "Failed to repair JSON: ${e.message}", "Repair Failed")
AnalyticsService.track(
AnalyticsConstant.REPAIR_FAILED, jsonData = input, additionaldata = e.message
)
}
null
}
}

private fun setRepairLoading(loading: Boolean) {
SwingUtilities.invokeLater {
repairButton?.isVisible = !loading
repairLoadingIndicator?.isVisible = loading
repairLoadingIndicator?.parent?.revalidate()
repairLoadingIndicator?.parent?.repaint()
if (loading) {
repairLoadingIndicator?.start()
} else {
repairLoadingIndicator?.stop()
}
showMergeRepair(input, repairedJson)
handleParse()
} catch (e: Exception) {
Messages.showErrorDialog(project, "Failed to repair JSON: ${e.message}", "Repair Failed")
AnalyticsService.track(AnalyticsConstant.REPAIR_FAILED, jsonData = input)
}
}

Expand Down Expand Up @@ -315,7 +346,16 @@ class ParserWidget(
private fun actionChooseFile() {
AnalyticsService.track(AnalyticsConstant.ACTION_LOAD_FILE)
FileChooser.chooseFile(
FileChooserDescriptor(true, false, false, false, false, false), project, null
FileChooserDescriptor(
true,
false,
false,
false,
false,
false
),
project,
null
) { file ->
try {
val content = String(file.contentsToByteArray()).replace("\r\n", "\n")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.godwin.jsonparser.ui.components

import java.awt.*
import java.awt.geom.Arc2D
import javax.swing.JComponent
import javax.swing.Timer

class CircularProgress(
private val strokeWidth: Int = 2,
private val trackColor: Color = Color(220, 220, 220),
private val progressColor: Color = Color(30, 144, 255),
private val cometTail: Boolean = true
) : JComponent() {

private var angle = 0
private val timer: Timer

init {
preferredSize = Dimension(100, 100)

// Rotate 10° every 20ms → smooth spin
timer = Timer(20) {
angle = (angle - 10) % 360
repaint()
}
timer.start()
}

fun stop() = timer.stop()
fun start() {
if (!timer.isRunning)
timer.start()
}

override fun paintComponent(g: Graphics) {
super.paintComponent(g)
val g2 = g.create() as Graphics2D

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)

val size = minOf(width, height) - strokeWidth * 2
val x = (width - size) / 2
val y = (height - size) / 2

// Background track
g2.stroke = BasicStroke(strokeWidth.toFloat(), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)
g2.color = trackColor
g2.drawOval(x, y, size, size)

if (cometTail) {
// Comet-tail effect: multiple arcs with increasing opacity
val arcLength = 90
val segments = 10

for (i in 0 until segments) {
val alpha = ((i + 1).toFloat() / segments * 255).toInt()
g2.color = Color(
progressColor.red,
progressColor.green,
progressColor.blue,
alpha
)
val segAngle = angle + (i * arcLength / segments)
g2.draw(
Arc2D.Float(
x.toFloat(), y.toFloat(), size.toFloat(), size.toFloat(),
segAngle.toFloat(), (arcLength / segments).toFloat(), Arc2D.OPEN
)
)
}
} else {
// Simple solid spinning arc
g2.color = progressColor
g2.draw(
Arc2D.Float(
x.toFloat(), y.toFloat(), size.toFloat(), size.toFloat(),
angle.toFloat(), 90f, Arc2D.OPEN
)
)
}

g2.dispose()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.godwin.jsonparser.ui.settings
import com.godwin.jsonparser.services.JsonPersistence
import com.intellij.openapi.options.Configurable
import com.intellij.ui.components.JBLabel
import java.awt.BorderLayout
import javax.swing.BoxLayout
import javax.swing.JCheckBox
import javax.swing.JComponent
Expand All @@ -12,6 +11,7 @@ import javax.swing.JPanel
class JsonParserSettingsConfigurable : Configurable {
private var analyticsCheckBox: JCheckBox? = null
private var errorJsonTracking: JCheckBox? = null
private var aiRepairEnabled: JCheckBox? = null

override fun getDisplayName() = "Json Parser"

Expand All @@ -24,26 +24,38 @@ class JsonParserSettingsConfigurable : Configurable {
"Enable logging of json string when repair doesn't worked",
JsonPersistence.getInstance().analyticsErrorJsonEnabled
)
aiRepairEnabled = JCheckBox(
"Enable fixing your json using AI (We are not storing any of your json anywhere)",
JsonPersistence.getInstance().repairUsingAi
)

val noteLabel =
JBLabel("<html><i>Note: Your string will be logged when repair doesn't worked. You can disabled this anytime.</i></html>")

val noteLabel = JBLabel("<html><i>Note: Your string will be logged when repair doesn't worked. You can disabled this anytime.</i></html>")

return JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
add(analyticsCheckBox)
add(errorJsonTracking)
add(aiRepairEnabled)
add(noteLabel)
}
}

override fun isModified(): Boolean {
return analyticsCheckBox?.isSelected != JsonPersistence.getInstance().analyticsEnabled
|| errorJsonTracking?.isSelected != JsonPersistence.getInstance().analyticsErrorJsonEnabled
|| aiRepairEnabled?.isSelected != JsonPersistence.getInstance().repairUsingAi
}

override fun apply() {
JsonPersistence.getInstance().analyticsEnabled = analyticsCheckBox?.isSelected ?: true
JsonPersistence.getInstance().analyticsErrorJsonEnabled = errorJsonTracking?.isSelected ?: true
JsonPersistence.getInstance().repairUsingAi = aiRepairEnabled?.isSelected ?: true
}

override fun reset() {
analyticsCheckBox?.isSelected = JsonPersistence.getInstance().analyticsEnabled
errorJsonTracking?.isSelected = JsonPersistence.getInstance().analyticsErrorJsonEnabled
aiRepairEnabled?.isSelected = JsonPersistence.getInstance().repairUsingAi
}
}
15 changes: 15 additions & 0 deletions src/main/kotlin/com/godwin/jsonparser/util/JsonUtils.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.godwin.jsonparser.util

import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.core.JsonProcessingException
import com.fasterxml.jackson.core.util.DefaultIndenter
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
import com.fasterxml.jackson.databind.DeserializationFeature
Expand Down Expand Up @@ -30,6 +31,20 @@ object JsonUtils {
}
}

fun isValidJsonError(jsonStr: String): String? {
return try {
ObjectMapper().readTree(jsonStr)
null
} catch (e: Exception) {
return if (e is JsonProcessingException) {
e.originalMessage
} else {
e.message
}
}
}


fun getMap(jsonStr: String): Any {
val node = mapper.readTree(jsonStr)

Expand Down
47 changes: 0 additions & 47 deletions src/main/kotlin/com/godwin/jsonparser/util/analytics/Analytics.kt

This file was deleted.

Loading
Loading