Skip to content

Commit 0c674ad

Browse files
committed
Initial Gradle Plugin configuration
1 parent f916d27 commit 0c674ad

File tree

12 files changed

+285
-44
lines changed

12 files changed

+285
-44
lines changed

app/src/processing/app/Preferences.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ fun loadPreferences(): Properties{
3434
}
3535
}
3636

37+
// TODO: Move this to a more appropriate place
3738
@Composable
3839
fun watchFile(file: File): Any? {
3940
val scope = rememberCoroutineScope()

app/src/processing/app/Sketch.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@
5050
* Stores information about files in the current sketch.
5151
*/
5252
public class Sketch {
53+
public static final String PROPERTIES_NAME = "sketch.properties";
54+
5355
private final Editor editor;
5456
private final Mode mode;
5557

@@ -1305,7 +1307,7 @@ static protected Settings loadProperties(File folder) throws IOException {
13051307
}
13061308
return null;
13071309
*/
1308-
return new Settings(new File(folder, "sketch.properties"));
1310+
return new Settings(new File(folder, PROPERTIES_NAME));
13091311
}
13101312

13111313

app/src/processing/app/gradle/GradleJob.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class GradleJob(
118118
val repository = getContentFile("repository").absolutePath.replace("""\""", """\\""")
119119
// Create the init.gradle.kts file in the working directory
120120
// This allows us to run the gradle plugin that has been bundled with the editor
121+
// TODO: Add the plugin repositories if they are defined
121122
val initGradle = workingDir.resolve("init.gradle.kts").apply {
122123
val content = """
123124
beforeSettings{
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package processing.app.gradle
2+
3+
import androidx.compose.runtime.mutableStateListOf
4+
import processing.app.Base
5+
import java.nio.file.Path
6+
7+
data class GradlePlugin(
8+
val name: String,
9+
val description: String,
10+
val repository: Path?,
11+
val id: String,
12+
val version: String){
13+
companion object{
14+
const val PROPERTIES_KEY = "sketch.plugins"
15+
val plugins = mutableStateListOf<GradlePlugin>(
16+
GradlePlugin("Hot Reload (experimental)", "Automatically apply changes in your sketch upon saving", null, "org.processing.java.hotreload", Base.getVersionName()),
17+
GradlePlugin("Android","Run your sketch on an Android device", null, "org.processing.android", Base.getVersionName()),
18+
)
19+
}
20+
}

app/src/processing/app/gradle/GradleService.kt

Lines changed: 9 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ package processing.app.gradle
22

33
import androidx.compose.runtime.mutableStateListOf
44
import androidx.compose.runtime.mutableStateOf
5+
import androidx.compose.ui.awt.ComposePanel
56
import processing.app.Language.text
67
import processing.app.Mode
78
import processing.app.Preferences
89
import processing.app.Sketch
910
import processing.app.ui.Editor
11+
import processing.app.ui.Theme
1012
import kotlin.io.path.createTempDirectory
1113

1214
// TODO: Highlight errors in the editor in the right place
@@ -28,17 +30,7 @@ class GradleService(
2830
val editor: Editor?,
2931
) {
3032
val active = mutableStateOf(Preferences.getBoolean("run.use_gradle"))
31-
32-
val settings = GradleSettings()
33-
34-
var sketch: Sketch? = null
35-
set (value) {
36-
field = value
37-
if(value == null) return
38-
// If the sketch is set, we start the build process to speed up the first run
39-
startJob("build")
40-
}
41-
33+
var sketch = mutableStateOf<Sketch?>(null)
4234
val jobs = mutableStateListOf<GradleJob>()
4335
val workingDir = createTempDirectory()
4436

@@ -61,7 +53,7 @@ class GradleService(
6153
val job = GradleJob(
6254
tasks = tasks,
6355
workingDir = workingDir,
64-
sketch = sketch ?: throw IllegalStateException("Sketch is not set"),
56+
sketch = sketch.value ?: throw IllegalStateException("Sketch is not set"),
6557
editor = editor
6658
)
6759
jobs.add(job)
@@ -72,18 +64,16 @@ class GradleService(
7264
jobs.forEach(GradleJob::cancel)
7365
}
7466

75-
// Hooks for java to check if the Gradle service is running since mutableStateOf is not accessible in java
67+
// Hooks for java to interact with the Gradle service since mutableStateOf is not accessible in java
68+
fun setSketch(sketch: Sketch){
69+
this.sketch.value = sketch
70+
startJob("build")
71+
}
7672
fun getEnabled(): Boolean {
7773
return active.value
7874
}
7975
fun setEnabled(active: Boolean) {
8076
if(!active) stopJobs()
8177
this.active.value = active
82-
val editor = editor ?: return
83-
if(active){
84-
editor.footer?.addPanel(settings, text("gradle.settings"), "/lib/footer/settings")
85-
}else{
86-
editor.footer?.removePanel(settings)
87-
}
8878
}
8979
}
Lines changed: 182 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,195 @@
11
package processing.app.gradle
22

3+
import androidx.compose.foundation.VerticalScrollbar
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.gestures.scrollable
6+
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Box
8+
import androidx.compose.foundation.layout.Column
9+
import androidx.compose.foundation.layout.Row
10+
import androidx.compose.foundation.layout.fillMaxHeight
11+
import androidx.compose.foundation.layout.fillMaxSize
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
14+
import androidx.compose.foundation.rememberScrollState
15+
import androidx.compose.foundation.rememberScrollbarAdapter
16+
import androidx.compose.foundation.verticalScroll
17+
import androidx.compose.material.Checkbox
18+
import androidx.compose.material.MaterialTheme
19+
import androidx.compose.material.Surface
320
import androidx.compose.material.Text
421
import androidx.compose.runtime.Composable
22+
import androidx.compose.runtime.LaunchedEffect
23+
import androidx.compose.runtime.getValue
24+
import androidx.compose.runtime.mutableStateOf
25+
import androidx.compose.runtime.remember
26+
import androidx.compose.runtime.setValue
27+
import androidx.compose.runtime.snapshotFlow
28+
import androidx.compose.ui.Alignment
29+
import androidx.compose.ui.Modifier
530
import androidx.compose.ui.awt.ComposePanel
31+
import androidx.compose.ui.awt.SwingPanel
32+
import androidx.compose.ui.graphics.Color
33+
import androidx.compose.ui.text.font.FontWeight
34+
import androidx.compose.ui.text.style.TextAlign
35+
import androidx.compose.ui.text.style.TextDecoration
36+
import androidx.compose.ui.unit.dp
37+
import androidx.compose.ui.unit.em
38+
import androidx.compose.ui.unit.sp
39+
import com.formdev.flatlaf.util.SwingUtils
40+
import com.github.ajalt.mordant.rendering.TextStyle
41+
import kotlinx.coroutines.CoroutineScope
42+
import kotlinx.coroutines.Dispatchers
43+
import kotlinx.coroutines.launch
44+
import processing.app.Language.text
45+
import processing.app.Settings
46+
import processing.app.Sketch
47+
import processing.app.ui.Editor
48+
import processing.app.ui.EditorFooter
49+
import processing.app.ui.Theme
50+
import processing.app.ui.theme.ProcessingTheme
51+
import processing.app.watchFile
52+
import java.awt.Dimension
53+
import java.util.UUID
54+
import javax.swing.JCheckBox
655
import javax.swing.JPanel
56+
import javax.swing.SwingUtilities
757

8-
class GradleSettings : JPanel() {
9-
init{
10-
val compose = ComposePanel()
11-
compose.setContent {
12-
Panel()
13-
}
14-
this.add(compose)
15-
}
58+
class GradleSettings{
1659
companion object{
60+
private val scope = CoroutineScope(Dispatchers.IO)
61+
62+
@JvmStatic
63+
fun addGradleSettings(footer: EditorFooter, service: GradleService){
64+
val panel = ComposePanel()
65+
panel.setContent {
66+
Panel(service)
67+
}
68+
scope.launch {
69+
// Only add the panel to the footer when Gradle is active
70+
// Can be removed later when Gradle becomes the default build system
71+
snapshotFlow { service.active.value }
72+
.collect { active ->
73+
SwingUtilities.invokeLater {
74+
if(active){
75+
footer.addPanel(panel, text("gradle.settings"), "/lib/footer/settings")
76+
}else{
77+
footer.removePanel(panel)
78+
}
79+
}
80+
}
81+
}
82+
}
83+
1784
@Composable
18-
fun Panel(){
19-
Text("Gradle settings will be here soon")
85+
fun Panel(service: GradleService){
86+
val properties = service.sketch.value?.folder?.resolve(Sketch.PROPERTIES_NAME) ?: return
87+
// TODO: Rewatch again is the sketch is saved in a different location
88+
89+
val changed = watchFile(properties)
90+
91+
val settings = remember(changed) {Settings(properties) }
92+
93+
LaunchedEffect(changed){
94+
/*
95+
If the sketch.id is not set, generate a new UUID and save it.
96+
We will use this key to save preferences that do not influence the sketch itself,
97+
so they are not code, but do influence how the sketch shows up in the editor.
98+
This is useful for things like favoring a sketch
99+
These are items that should not be shared between users/computers
100+
// TODO: Reset id on save-as?
101+
*/
102+
if(settings.get("sketch.id") == null){
103+
// TODO: Should this watch the file or should it update a bunch on running the sketch?
104+
settings.set("sketch.id", UUID.randomUUID().toString())
105+
settings.save()
106+
}
107+
}
108+
val stateVertical = rememberScrollState(0)
109+
110+
ProcessingTheme {
111+
Box {
112+
Row(
113+
modifier = Modifier
114+
.background(Color(Theme.getColor("editor.line.highlight.color").rgb))
115+
.padding(start = Editor.LEFT_GUTTER.dp)
116+
.fillMaxSize()
117+
.verticalScroll(stateVertical)
118+
.padding(vertical = 4.dp)
119+
) {
120+
PluginsPanel(settings)
121+
}
122+
VerticalScrollbar(
123+
modifier = Modifier
124+
.align(Alignment.CenterEnd)
125+
.padding(8.dp)
126+
.fillMaxHeight(),
127+
adapter = rememberScrollbarAdapter(stateVertical)
128+
)
129+
}
130+
}
20131
}
21132

133+
@Composable
134+
private fun PluginsPanel(settings: Settings) {
135+
// Grab the installed plugins
136+
val plugins = GradlePlugin.plugins
137+
138+
// Grab the enabled plugins
139+
val pluginSetting = (settings.get(GradlePlugin.PROPERTIES_KEY) ?: "")
140+
.split(",")
141+
.map { it.trim() }
142+
.filter{ it.isNotEmpty() }
143+
144+
// Link plugins in the settings to their installed counterparts
145+
val enabledPlugins = pluginSetting
146+
.map { id -> plugins.find { plugin -> plugin.id == id } }
147+
Column {
148+
Text(
149+
text = text("gradle.settings.plugins"),
150+
textAlign = TextAlign.Start,
151+
fontSize = 10.sp,
152+
fontWeight = FontWeight.Bold
153+
)
154+
Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
155+
GradlePlugin.plugins.map { plugin ->
156+
Row() {
157+
Checkbox(
158+
checked = enabledPlugins.contains(plugin),
159+
modifier = Modifier
160+
.padding(start = 0.dp, end = 8.dp)
161+
.size(24.dp),
162+
onCheckedChange = { checked ->
163+
scope.launch {
164+
// Work from the setting as we do not want to remove missing plugins
165+
val current = pluginSetting.toMutableSet()
166+
if (checked) {
167+
current.add(plugin.id)
168+
} else {
169+
current.remove(plugin.id)
170+
}
171+
settings.set(GradlePlugin.PROPERTIES_KEY, current.joinToString(","))
172+
settings.save()
173+
}
174+
},
175+
)
176+
Column {
177+
Text(
178+
text = plugin.name,
179+
textAlign = TextAlign.Start,
180+
fontSize = 12.sp
181+
)
182+
Text(
183+
text = plugin.description,
184+
textAlign = TextAlign.Start,
185+
fontSize = 10.sp,
186+
)
187+
}
188+
}
189+
190+
}
191+
}
192+
}
193+
}
22194
}
23195
}

app/src/processing/app/gradle/api/Sketch.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class Sketch : SuspendingCliktCommand("sketch") {
5353
System.setProperty("java.awt.headless", "false")
5454

5555
val service = GradleService(mode,null)
56-
service.sketch = processing.app.Sketch(sketch, mode)
56+
service.sketch.value = processing.app.Sketch(sketch, mode)
5757
service.run()
5858

5959
// TODO: Use an async way to wait for the job to finish

app/src/processing/app/ui/EditorFooter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ public void addPanel(Component comp, String name) {
152152
public void addPanel(Component comp, String name, String icon) {
153153
tabs.add(new Tab(comp, name, icon));
154154
cardPanel.add(name, comp);
155+
repaint();
155156
}
156157

157158
/**
Lines changed: 8 additions & 1 deletion
Loading

build/shared/lib/languages/PDE.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,7 @@ gradle.instructions = About this file: \nProcessing creates this file when you r
325325
gradle.using_gradle = Building sketch using the new build system. (See settings to switch to the legacy build system.)
326326
gradle.using_eclipse = Building sketch using the legacy build system. (See settings to switch to the new build system.)
327327
gradle.settings = Settings
328+
gradle.settings.plugins = Plugins
328329

329330
# ---------------------------------------
330331
# Toolbars

0 commit comments

Comments
 (0)