Skip to content

New Welcome Screen #963

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 20 commits into
base: main
Choose a base branch
from
Draft
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
File renamed without changes.
7 changes: 6 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import org.gradle.kotlin.dsl.support.zipTo
import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
import org.jetbrains.compose.ExperimentalComposeLibrary
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import org.jetbrains.compose.desktop.application.tasks.AbstractJPackageTask
import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download
@@ -59,7 +60,7 @@ compose.desktop {
).map { "-D${it.first}=${it.second}" }.toTypedArray())

nativeDistributions{
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "java.management.rmi")
modules("jdk.jdi", "java.compiler", "jdk.accessibility", "jdk.zipfs", "java.management.rmi")
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "Processing"

@@ -109,6 +110,7 @@ dependencies {
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(compose.materialIconsExtended)

implementation(compose.desktop.currentOs)

@@ -121,6 +123,9 @@ dependencies {
testImplementation(libs.mockitoKotlin)
testImplementation(libs.junitJupiter)
testImplementation(libs.junitJupiterParams)

@OptIn(ExperimentalComposeLibrary::class)
testImplementation(compose.uiTest)
}

tasks.test {
Binary file added app/src/main/resources/default.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions app/src/main/resources/welcome/intro/bubble.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions app/src/main/resources/welcome/intro/long.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions app/src/main/resources/welcome/intro/short.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions app/src/main/resources/welcome/intro/wavy.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/src/processing/app/Language.java
Original file line number Diff line number Diff line change
@@ -183,6 +183,12 @@ static public Language init() {
return instance;
}

static public void reload(){
if(instance == null) return;
synchronized (Language.class) {
instance = new Language();
}
}

static private String get(String key) {
LanguageBundle bundle = init().bundle;
74 changes: 55 additions & 19 deletions app/src/processing/app/Preferences.kt
Original file line number Diff line number Diff line change
@@ -2,38 +2,82 @@ package processing.app

import androidx.compose.runtime.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.dropWhile
import kotlinx.coroutines.launch
import java.io.File
import java.io.InputStream
import java.io.OutputStream
import java.nio.file.*
import java.util.Properties


const val PREFERENCES_FILE_NAME = "preferences.txt"
const val DEFAULTS_FILE_NAME = "defaults.txt"

fun PlatformStart(){
Platform.inst ?: Platform.init()
}
class ReactiveProperties: Properties() {
val _stateMap = mutableStateMapOf<String, String>()

override fun setProperty(key: String, value: String) {
super.setProperty(key, value)
_stateMap[key] = value
}

override fun getProperty(key: String): String? {
return _stateMap[key] ?: super.getProperty(key)
}

operator fun get(key: String): String? = getProperty(key)

operator fun set(key: String, value: String) {
setProperty(key, value)
}
}
val LocalPreferences = compositionLocalOf<ReactiveProperties> { error("No preferences provided") }
@OptIn(FlowPreview::class)
@Composable
fun loadPreferences(): Properties{
PlatformStart()
fun PreferencesProvider(content: @Composable () -> Unit){
remember {
Platform.init()
}

val settingsFolder = Platform.getSettingsFolder()
val preferencesFile = settingsFolder.resolve(PREFERENCES_FILE_NAME)

if(!preferencesFile.exists()){
preferencesFile.mkdirs()
preferencesFile.createNewFile()
}
watchFile(preferencesFile)

return Properties().apply {
load(ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME) ?: InputStream.nullInputStream())
load(preferencesFile.inputStream())
val update = watchFile(preferencesFile)
val properties = remember(preferencesFile, update) { ReactiveProperties().apply {
load((ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME)?: InputStream.nullInputStream()).reader(Charsets.UTF_8))
load(preferencesFile.inputStream().reader(Charsets.UTF_8))
}}

val initialState = remember(properties) { properties._stateMap.toMap() }

LaunchedEffect(properties) {
snapshotFlow { properties._stateMap.toMap() }
.dropWhile { it == initialState }
.debounce(100)
.collect {
preferencesFile.outputStream().use { output ->
output.write(
properties.entries
.sortedWith(compareBy(String.CASE_INSENSITIVE_ORDER) { it.key.toString() })
.joinToString("\n") { (key, value) -> "$key=$value" }
.toByteArray()
)
}
}
}

CompositionLocalProvider(LocalPreferences provides properties){
content()
}
}

}
@Composable
fun watchFile(file: File): Any? {
val scope = rememberCoroutineScope()
@@ -62,12 +106,4 @@ fun watchFile(file: File): Any? {
}
}
return event
}
val LocalPreferences = compositionLocalOf<Properties> { error("No preferences provided") }
@Composable
fun PreferencesProvider(content: @Composable () -> Unit){
val preferences = loadPreferences()
CompositionLocalProvider(LocalPreferences provides preferences){
content()
}
}
9 changes: 5 additions & 4 deletions app/src/processing/app/contrib/ui/ContributionManager.kt
Original file line number Diff line number Diff line change
@@ -22,8 +22,9 @@ import androidx.compose.ui.window.application
import com.charleskorn.kaml.Yaml
import com.charleskorn.kaml.YamlConfiguration
import kotlinx.serialization.Serializable
import processing.app.LocalPreferences
import processing.app.Platform
import processing.app.loadPreferences
import processing.app.ReactiveProperties
import java.net.URL
import java.util.*
import javax.swing.JFrame
@@ -106,7 +107,7 @@ fun contributionsManager(){
var localContributions by remember { mutableStateOf(listOf<Contribution>()) }
var error by remember { mutableStateOf<Exception?>(null) }

val preferences = loadPreferences()
val preferences = LocalPreferences.current

LaunchedEffect(preferences){
try {
@@ -284,9 +285,9 @@ fun contributionsManager(){
}


fun loadContributionProperties(preferences: Properties): List<Pair<Type, Properties>>{
fun loadContributionProperties(preferences: ReactiveProperties): List<Pair<Type, Properties>>{
val result = mutableListOf<Pair<Type, Properties>>()
val sketchBook = Path(preferences.getProperty("sketchbook.path.four", Platform.getDefaultSketchbookFolder().path))
val sketchBook = Path(preferences.getProperty("sketchbook.path.four") ?: Platform.getDefaultSketchbookFolder().path)
sketchBook.forEachDirectoryEntry{ contributionsFolder ->
if(!contributionsFolder.isDirectory()) return@forEachDirectoryEntry
val typeName = contributionsFolder.fileName.toString()
Loading