diff --git a/app/ant/processing/app/ui/WelcomeToBeta.java b/app/ant/processing/app/ui/WelcomeToBeta.java new file mode 100644 index 000000000..3127e4adc --- /dev/null +++ b/app/ant/processing/app/ui/WelcomeToBeta.java @@ -0,0 +1,11 @@ +package processing.app.ui; + + +// Stub class for backwards compatibility with the ant-build system +// This class is not used in the Gradle build system +// The actual implementation is in src/.../Schema.kt +public class WelcomeToBeta { + public static void showWelcomeToBeta(){ + + } +} diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 2bd30a09d..8c62f07bf 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -2,6 +2,8 @@ import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.internal.de.undercouch.gradle.tasks.download.Download +// TODO: Update to 2.10.20 and add hot-reloading: https://github.com/JetBrains/compose-hot-reload + plugins{ id("java") kotlin("jvm") version libs.versions.kotlin @@ -29,6 +31,9 @@ sourceSets{ kotlin{ srcDirs("src") } + resources{ + srcDirs("resources", listOf("languages", "fonts", "theme").map { "../build/shared/lib/$it" }) + } } test{ kotlin{ @@ -104,6 +109,8 @@ dependencies { implementation(libs.compottie) implementation(libs.kaml) + implementation(libs.markdown) + implementation(libs.markdownJVM) testImplementation(kotlin("test")) testImplementation(libs.mockitoKotlin) diff --git a/app/src/main/resources/bird.svg b/app/src/main/resources/bird.svg new file mode 100644 index 000000000..90d69c899 --- /dev/null +++ b/app/src/main/resources/bird.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/app/src/main/resources/defaults.txt b/app/src/main/resources/defaults.txt new file mode 100644 index 000000000..6e3e00f0d --- /dev/null +++ b/app/src/main/resources/defaults.txt @@ -0,0 +1,309 @@ +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +# DO NOT MAKE CHANGES TO THIS FILE!!! + +# These are the default preferences. If you want to modify +# them directly, use the per-user local version of the file: + +# Users -> [username] -> AppData -> Roaming -> +# Processing -> preferences.txt (on Windows 10) + +# ~/Library -> Processing -> preferences.txt (on macOS) + +# ~/.config/processing -> preferences.txt (on Linux) + +# The exact location of your preferences file can be found at +# the bottom of the Preferences window inside Processing. + +# Because AppData and Application Data may be considered +# hidden or system folders on Windows, you'll have to ensure +# that they're visible in order to get at preferences.txt + +# You'll have problems running Processing if you incorrectly +# modify lines in this file. It will probably not start at all. + +# AGAIN, DO NOT ALTER THIS FILE! I'M ONLY YELLING BECAUSE I LOVE YOU! + + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +# If you don't want users to have their sketchbook default to +# "My Documents/Processing" on Windows and "Documents/Processing" on OS X, +# set this to another path that will be used by default. +# Note that this path must exist already otherwise it won't see +# the sketchbook folder, and will instead assume the sketchbook +# has gone missing, and that it should instead use the default. +# In 4.0, the location has changed. +#sketchbook.path.four= + +# Whether or not to show the Welcome screen for 4.0 +# (It's always available under Help → Welcome) +welcome.four.show = true +welcome.four.seen = false + +# Set 'true' for the default behavior before 4.0, where the +# main tab must have the same name as the sketch folder +editor.sync_folder_and_filename = true + +# By default, contributions are moved to backup folders when +# they are removed or replaced. The backups can be found at +# sketchbook/libraries/old, sketchbook/tools/old, and sketchbook/modes/old + +# true to backup contributions when "Remove" button is pressed +contribution.backup.on_remove = true +# true to backup contributions when installing a newer version +contribution.backup.on_install = true + +recent.count = 10 + +# Default to the native (AWT) file selector where possible +chooser.files.native = true +# We were shutting this off on macOS because it broke Copy/Paste: +# https://github.com/processing/processing/issues/1035 +# But removing again for 4.0 alpha 5, because the JFileChooser is awful, +# and worse on Big Sur, so a bigger problem than the Copy/Paste issue. +# https://github.com/processing/processing4/issues/77 +#chooser.files.native.macos = false + +# set to 'lab' to interpolate theme gradients using L*a*b* color space +theme.gradient.method = rgb + + +# by default, check the processing server for any updates +# (please avoid disabling, this also helps us know basic numbers +# on how many people are using Processing) +update.check = true + +# on windows, automatically associate .pde files with processing.exe +platform.auto_file_type_associations = true + + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +# default size for the main window +editor.window.width.default = 700 +editor.window.height.default = 600 + +editor.window.width.min = 400 +editor.window.height.min = 500 +# tested as approx 440 on OS X +editor.window.height.min.macos = 450 +# tested to be 515 on Windows XP, this leaves some room +editor.window.height.min.windows = 530 +# tested with Raspberry Pi display +editor.window.height.min.linux = 480 + +# scaling for the interface (to handle Windows and Linux HiDPI displays) +editor.zoom = 100% +# automatically set based on system dpi (only helps on Windows) +editor.zoom.auto = true + +# Use the default monospace font included in lib/fonts. +# (As of Processing 4 alpha 5, that's Source Code Pro) +editor.font.family = processing.mono +editor.font.size = 12 + +# To reset everyone's default, replaced editor.antialias with editor.smooth +# for 2.1. Fonts are unusably gross on OS X (and Linux) w/o smoothing and +# the Oracle JVM, and many longtime users have anti-aliasing turned off. +editor.smooth = true + +# blink the caret by default +editor.caret.blink = true +# change to true to use a block (instead of a bar) +editor.caret.block = false + +# enable ctrl-ins, shift-ins, shift-delete for cut/copy/paste +# on windows and linux, but disable on the mac +editor.keys.alternative_cut_copy_paste = true +editor.keys.alternative_cut_copy_paste.macos = false + +# true if shift-backspace sends the delete character, +# false if shift-backspace just means backspace +editor.keys.shift_backspace_is_delete = false + +# home and end keys should only travel to the start/end of the current line +editor.keys.home_and_end_travel_far = false +# home and end keys move to the first/last non-whitespace character, +# and move to the actual start/end when pressed a second time. +# Only works if editor.keys.home_and_end_travel_far is false. +editor.keys.home_and_end_travel_smart = true +# The OS X HI Guidelines say that home/end are relative to the document, +# but that drives some people nuts. This pref enables/disables it. +editor.keys.home_and_end_travel_far.macos = true + +# Enable/disable support for complex scripts. Used for Japanese and others, +# but disable when not needed, otherwise basic Western European chars break. +editor.input_method_support = false + +# convert tabs to spaces? how many spaces? +editor.tabs.expand = true +editor.tabs.size = 2 + +# Set to true to automatically close [ { ( " and ' +editor.completion.auto_close = false + +# automatically indent each line +editor.indent = true + +# Whether to check files to see if they've been modified externally +editor.watcher = true +# Set true to enable debugging, since this is quirky on others' machines +editor.watcher.debug = false +# The window of time (in milliseconds) in which a change won't be counted +editor.watcher.window = 1500 + +# Format and search engine to use for online queries +search.format = https://google.com/search?q=%s + +# font choice and size for the console +console.font.size = 12 + +# number of lines to show by default +console.lines = 4 + +# Number of blank lines to advance/clear console. +# Note that those lines are also printed in the terminal when +# Processing is executed there. +# Setting to 0 stops this behavior. +console.head_padding = 10 + +# Set to false to disable automatically clearing the console +# each time 'run' is hit +# If one sets it to false, one may also want to set 'console.head_padding' +# to a positive number to separate outputs from different runs. +console.auto_clear = true + +# number of days of history to keep around before cleaning +# setting to 0 will never clean files +console.temp.days = 7 + +# set the maximum number of lines remembered by the console +# the default is 500, lengthen at your own peril +console.scrollback.lines = 500 +console.scrollback.chars = 40000 + +# Any additional Java options when running. +# If you change this and can't run things, it's your own durn fault. +run.options = + +# settings for the -XmsNNNm and -XmxNNNm command line option +run.options.memory = false +run.options.memory.initial = 64 +run.options.memory.maximum = 512 + +# Index of the display to use for running sketches (starts at 1). +# Kept this 1-indexed because older vesions of Processing were setting +# the preference even before it was being used. +# -1 means the default display, 0 means all displays +run.display = -1 + +# set internally because it comes from the system +#run.window.bgcolor= + +# set to false to open a new untitled window when closing the last window +# (otherwise, the environment will quit) +# default to the relative norm for the different platforms, +# but the setting can be changed in the prefs dialog anyway +#sketchbook.closing_last_window_quits = true +#sketchbook.closing_last_window_quits.macos = false + +editor.untitled.prefix=sketch_ +# The old (pre-1.0, back for 2.0) style for default sketch name. +# If you change this, be careful that this will work with your language +# settings. For instance, MMMdd won't work on Korean-language systems +# because it'll insert non-ASCII characters and break the environment. +# https://github.com/processing/processing/issues/322 +editor.untitled.suffix=yyMMdd + +# replace underscores in .pde file names with spaces +sketch.name.replace_underscore = true + +# what to use for generating sketch names (change in the prefs window) +#sketch.name.approach = + +# number of days of build history and other temp files to keep around +# these are kept around for debugging purposes, and in case code is lost +temp.days = 7 + + +# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + +# whether or not to export as full screen (present) mode +export.application.fullscreen = false + +# whether to show the stop button when exporting to application +export.application.stop = true + +# embed Java by default for lower likelihood of problems +export.application.embed_java = true + +# set to false to no longer delete application folders before export +# (removed from the Preferences windows in 4.0 beta 9) +export.delete_target_folder = true + +# may be useful when attempting to debug the preprocessor +preproc.save_build_files=false + +# allows various preprocessor features to be toggled +# in case they are causing problems + +# preprocessor: pde.g +preproc.color_datatype = true +preproc.web_colors = true +preproc.enhanced_casting = true + +# preprocessor: PdeEmitter.java +preproc.substitute_floats = true + +# PdePreproc.java +# writes out the parse tree as parseTree.xml, which can be usefully +# viewed in (at least) Mozilla or IE. useful when debugging the preprocessor. +preproc.output_parse_tree = false + +# set to the program to be used for opening HTML files, folders, etc. +#launcher.linux = xdg-open + +# FULL SCREEN (PRESENT MODE) +run.present.bgcolor = #666666 +run.present.stop.color = #cccccc + +# PROXIES +# Set a proxy server for folks that require it. This will allow the update +# checker and the contrib manager to run properly in those environments. +# This changed from proxy.host and proxy.port to proxy.http.host and +# proxy.http.port in 3.0a8. In addition, https and socks were added. +proxy.http.host= +proxy.http.port= +proxy.https.host= +proxy.https.port= +proxy.socks.host= +proxy.socks.port= +# Example of usage (replace 'http' with 'https' or 'socks' as needed) +#proxy.http.host=proxy.example.com +#proxy.http.port=8080 +# Whether to use the system proxy by default +proxy.system=true + +# PDE X +pdex.errorCheckEnabled = true +pdex.warningsEnabled = true +pdex.writeErrorLogs = false + +pdex.autoSave.autoSaveEnabled = false +pdex.autoSaveInterval = 5 +pdex.autoSave.promptDisplay = true +pdex.autoSave.autoSaveByDefault = true + +# Enable auto-completion when hitting ctrl-space +pdex.completion = false +# Setting this true will show completions whenever available, not just after ctrl-space +pdex.completion.trigger = false +# Suggest libraries to import when a class is undefined/unavailable +pdex.suggest.imports = true +# Set to false to disable ctrl/cmd-click jump to definition +pdex.inspectMode.hotkey = true diff --git a/app/src/main/resources/logo.svg b/app/src/main/resources/logo.svg new file mode 100644 index 000000000..aa04fcb29 --- /dev/null +++ b/app/src/main/resources/logo.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/app/src/processing/app/contrib/ui/Preferences.kt b/app/src/processing/app/Preferences.kt similarity index 69% rename from app/src/processing/app/contrib/ui/Preferences.kt rename to app/src/processing/app/Preferences.kt index b344e1cb7..c5645c9bb 100644 --- a/app/src/processing/app/contrib/ui/Preferences.kt +++ b/app/src/processing/app/Preferences.kt @@ -1,11 +1,10 @@ -package processing.app.contrib.ui +package processing.app import androidx.compose.runtime.* import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import processing.app.Base -import processing.app.Platform import java.io.File +import java.io.InputStream import java.nio.file.* import java.util.Properties @@ -13,10 +12,13 @@ import java.util.Properties const val PREFERENCES_FILE_NAME = "preferences.txt" const val DEFAULTS_FILE_NAME = "defaults.txt" +fun PlatformStart(){ + Platform.inst ?: Platform.init() +} @Composable fun loadPreferences(): Properties{ - Platform.init() + PlatformStart() val settingsFolder = Platform.getSettingsFolder() val preferencesFile = settingsFolder.resolve(PREFERENCES_FILE_NAME) @@ -24,20 +26,12 @@ fun loadPreferences(): Properties{ if(!preferencesFile.exists()){ preferencesFile.createNewFile() } - val watched = watchFile(preferencesFile) - - val preferences by remember { - mutableStateOf(Properties()) - } - - LaunchedEffect(watched){ - val defaults = Base::class.java.getResourceAsStream("/lib/${DEFAULTS_FILE_NAME}") ?: return@LaunchedEffect + watchFile(preferencesFile) - preferences.load(defaults) - preferences.load(preferencesFile.inputStream()) + return Properties().apply { + load(ClassLoader.getSystemResourceAsStream(DEFAULTS_FILE_NAME) ?: InputStream.nullInputStream()) + load(preferencesFile.inputStream()) } - - return preferences } @Composable @@ -68,4 +62,12 @@ fun watchFile(file: File): Any? { } } return event +} +val LocalPreferences = compositionLocalOf { error("No preferences provided") } +@Composable +fun PreferencesProvider(content: @Composable () -> Unit){ + val preferences = loadPreferences() + CompositionLocalProvider(LocalPreferences provides preferences){ + content() + } } \ No newline at end of file diff --git a/app/src/processing/app/UpdateCheck.java b/app/src/processing/app/UpdateCheck.java index 40ffe24c0..1bfa29688 100644 --- a/app/src/processing/app/UpdateCheck.java +++ b/app/src/processing/app/UpdateCheck.java @@ -31,6 +31,7 @@ import javax.swing.JOptionPane; +import processing.app.ui.WelcomeToBeta; import processing.core.PApplet; @@ -116,7 +117,7 @@ public void updateCheck() throws IOException { long now = System.currentTimeMillis(); if (lastString != null) { long when = Long.parseLong(lastString); - if (now - when < ONE_DAY) { + if (now - when < ONE_DAY && !Base.DEBUG) { // don't annoy the shit outta people return; } @@ -134,6 +135,9 @@ public void updateCheck() throws IOException { // offerToUpdateContributions = !promptToVisitDownloadPage(); promptToVisitDownloadPage(); } + if(latest < Base.getRevision()){ + WelcomeToBeta.showWelcomeToBeta(); + } /* if (offerToUpdateContributions) { diff --git a/app/src/processing/app/contrib/ui/ContributionManager.kt b/app/src/processing/app/contrib/ui/ContributionManager.kt index a057e76df..2ad472159 100644 --- a/app/src/processing/app/contrib/ui/ContributionManager.kt +++ b/app/src/processing/app/contrib/ui/ContributionManager.kt @@ -12,8 +12,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.awt.ComposePanel import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.key.Key -import androidx.compose.ui.input.key.key import androidx.compose.ui.input.pointer.PointerIcon import androidx.compose.ui.input.pointer.pointerHoverIcon import androidx.compose.ui.text.font.FontWeight @@ -25,6 +23,7 @@ import com.charleskorn.kaml.Yaml import com.charleskorn.kaml.YamlConfiguration import kotlinx.serialization.Serializable import processing.app.Platform +import processing.app.loadPreferences import java.net.URL import java.util.* import javax.swing.JFrame @@ -33,16 +32,7 @@ import kotlin.io.path.* fun main() = application { - val active = remember { mutableStateOf(true) } - if(!active.value){ - Window(onCloseRequest = ::exitApplication) { - - } - return@application - } - Window( - onCloseRequest = { active.value = false }, - ) { + Window(onCloseRequest = ::exitApplication) { contributionsManager() } } diff --git a/app/src/processing/app/ui/WelcomeToBeta.kt b/app/src/processing/app/ui/WelcomeToBeta.kt new file mode 100644 index 000000000..d7492fa6a --- /dev/null +++ b/app/src/processing/app/ui/WelcomeToBeta.kt @@ -0,0 +1,211 @@ +package processing.app.ui + +import androidx.compose.animation.animateColorAsState +import androidx.compose.animation.core.animateFloatAsState +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.* +import androidx.compose.material.MaterialTheme +import androidx.compose.material.MaterialTheme.colors +import androidx.compose.material.MaterialTheme.typography +import androidx.compose.material.Surface +import androidx.compose.material.Text +import androidx.compose.runtime.* +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.awt.ComposePanel +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerEventType +import androidx.compose.ui.input.pointer.PointerIcon +import androidx.compose.ui.input.pointer.onPointerEvent +import androidx.compose.ui.input.pointer.pointerHoverIcon +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.DpSize +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.compose.ui.window.Window +import androidx.compose.ui.window.WindowPosition +import androidx.compose.ui.window.application +import androidx.compose.ui.window.rememberWindowState +import com.formdev.flatlaf.util.SystemInfo +import com.mikepenz.markdown.compose.Markdown +import com.mikepenz.markdown.m2.markdownColor +import com.mikepenz.markdown.m2.markdownTypography +import com.mikepenz.markdown.model.MarkdownColors +import com.mikepenz.markdown.model.MarkdownTypography +import processing.app.Base.getRevision +import processing.app.Base.getVersionName +import processing.app.ui.theme.LocalLocale +import processing.app.ui.theme.LocalTheme +import processing.app.ui.theme.Locale +import processing.app.ui.theme.ProcessingTheme +import java.awt.Cursor +import java.awt.Dimension +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import java.io.InputStream +import java.util.Properties +import javax.swing.JFrame +import javax.swing.SwingUtilities + + +class WelcomeToBeta { + companion object{ + val windowSize = Dimension(400, 200) + val windowTitle = Locale()["beta.window.title"] + + @JvmStatic + fun showWelcomeToBeta() { + val mac = SystemInfo.isMacFullWindowContentSupported + SwingUtilities.invokeLater { + JFrame(windowTitle).apply { + val close = { dispose() } + rootPane.putClientProperty("apple.awt.transparentTitleBar", mac) + rootPane.putClientProperty("apple.awt.fullWindowContent", mac) + defaultCloseOperation = JFrame.DISPOSE_ON_CLOSE + contentPane.add(ComposePanel().apply { + size = windowSize + setContent { + ProcessingTheme { + Box(modifier = Modifier.padding(top = if (mac) 22.dp else 0.dp)) { + welcomeToBeta(close) + } + } + } + }) + pack() + background = java.awt.Color.white + setLocationRelativeTo(null) + addKeyListener(object : KeyAdapter() { + override fun keyPressed(e: KeyEvent) { + if (e.keyCode == KeyEvent.VK_ESCAPE) close() + } + }) + isResizable = false + isVisible = true + requestFocus() + } + } + } + + @Composable + fun welcomeToBeta(close: () -> Unit = {}) { + Row( + modifier = Modifier + .padding(20.dp, 10.dp) + .size(windowSize.width.dp, windowSize.height.dp), + horizontalArrangement = Arrangement + .spacedBy(20.dp) + ){ + val locale = LocalLocale.current + Image( + painter = painterResource("bird.svg"), + contentDescription = locale["beta.logo"], + modifier = Modifier + .align(Alignment.CenterVertically) + .size(100.dp, 100.dp) + .offset(0.dp, (-25).dp) + ) + Column( + modifier = Modifier + .fillMaxHeight(), + verticalArrangement = Arrangement + .spacedBy( + 10.dp, + alignment = Alignment.CenterVertically + ) + ) { + Text( + text = locale["beta.title"], + style = typography.subtitle1, + ) + val text = locale["beta.message"] + .replace('$' + "version", getVersionName()) + .replace('$' + "revision", getRevision().toString()) + Markdown( + text, + colors = markdownColor(), + typography = markdownTypography(text = typography.body1, link = typography.body1.copy(color = colors.primary)), + modifier = Modifier.background(Color.Transparent).padding(bottom = 10.dp) + ) + Row { + Spacer(modifier = Modifier.weight(1f)) + PDEButton(onClick = { + close() + }) { + Text( + text = locale["beta.button"], + color = colors.onPrimary + ) + } + } + } + } + } + @OptIn(ExperimentalComposeUiApi::class) + @Composable + fun PDEButton(onClick: () -> Unit, content: @Composable BoxScope.() -> Unit) { + val theme = LocalTheme.current + + var hover by remember { mutableStateOf(false) } + var clicked by remember { mutableStateOf(false) } + val offset by animateFloatAsState(if (hover) -5f else 5f) + val color by animateColorAsState(if(clicked) colors.primaryVariant else colors.primary) + + Box(modifier = Modifier.padding(end = 5.dp, top = 5.dp)) { + Box( + modifier = Modifier + .offset((-offset).dp, (offset).dp) + .background(theme.getColor("toolbar.button.pressed.field")) + .matchParentSize() + ) + Box( + modifier = Modifier + .onPointerEvent(PointerEventType.Press) { + clicked = true + } + .onPointerEvent(PointerEventType.Release) { + clicked = false + onClick() + } + .onPointerEvent(PointerEventType.Enter) { + hover = true + } + .onPointerEvent(PointerEventType.Exit) { + hover = false + } + .pointerHoverIcon(PointerIcon(Cursor(Cursor.HAND_CURSOR))) + .background(color) + .padding(10.dp) + .sizeIn(minWidth = 100.dp), + contentAlignment = Alignment.Center, + content = content + ) + } + } + + + @JvmStatic + fun main(args: Array) { + application { + val windowState = rememberWindowState( + size = DpSize.Unspecified, + position = WindowPosition(Alignment.Center) + ) + + Window(onCloseRequest = ::exitApplication, state = windowState, title = windowTitle) { + ProcessingTheme { + Surface(color = colors.background) { + welcomeToBeta { + exitApplication() + } + } + } + } + } + } + } +} + diff --git a/app/src/processing/app/ui/theme/Locale.kt b/app/src/processing/app/ui/theme/Locale.kt new file mode 100644 index 000000000..254c0946c --- /dev/null +++ b/app/src/processing/app/ui/theme/Locale.kt @@ -0,0 +1,45 @@ +package processing.app.ui.theme + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import processing.app.LocalPreferences +import processing.app.Messages +import processing.app.Platform +import processing.app.PlatformStart +import processing.app.watchFile +import java.io.File +import java.io.InputStream +import java.util.* + +class Locale(language: String = "") : Properties() { + init { + val locale = java.util.Locale.getDefault() + load(ClassLoader.getSystemResourceAsStream("PDE.properties")) + load(ClassLoader.getSystemResourceAsStream("PDE_${locale.language}.properties") ?: InputStream.nullInputStream()) + load(ClassLoader.getSystemResourceAsStream("PDE_${locale.toLanguageTag()}.properties") ?: InputStream.nullInputStream()) + load(ClassLoader.getSystemResourceAsStream("PDE_${language}.properties") ?: InputStream.nullInputStream()) + } + + @Deprecated("Use get instead", ReplaceWith("get(key)")) + override fun getProperty(key: String?, default: String): String { + val value = super.getProperty(key, default) + if(value == default) Messages.log("Missing translation for $key") + return value + } + operator fun get(key: String): String = getProperty(key, key) +} +val LocalLocale = compositionLocalOf { Locale() } +@Composable +fun LocaleProvider(content: @Composable () -> Unit) { + PlatformStart() + + val settingsFolder = Platform.getSettingsFolder() + val languageFile = File(settingsFolder, "language.txt") + watchFile(languageFile) + + val locale = Locale(languageFile.readText().substring(0, 2)) + CompositionLocalProvider(LocalLocale provides locale) { + content() + } +} \ No newline at end of file diff --git a/app/src/processing/app/ui/theme/Theme.kt b/app/src/processing/app/ui/theme/Theme.kt new file mode 100644 index 000000000..735d8e5b2 --- /dev/null +++ b/app/src/processing/app/ui/theme/Theme.kt @@ -0,0 +1,75 @@ +package processing.app.ui.theme + +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material.Colors +import androidx.compose.material.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.ui.graphics.Color +import processing.app.LocalPreferences +import processing.app.PreferencesProvider +import java.io.InputStream +import java.util.Properties + + +class Theme(themeFile: String? = "") : Properties() { + init { + load(ClassLoader.getSystemResourceAsStream("theme.txt")) + load(ClassLoader.getSystemResourceAsStream(themeFile) ?: InputStream.nullInputStream()) + } + fun getColor(key: String): Color { + return Color(getProperty(key).toColorInt()) + } +} + +val LocalTheme = compositionLocalOf { error("No theme provided") } + +@Composable +fun ProcessingTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + content: @Composable() () -> Unit +) { + PreferencesProvider { + val preferences = LocalPreferences.current + val theme = Theme(preferences.getProperty("theme")) + val colors = Colors( + primary = theme.getColor("editor.gradient.top"), + primaryVariant = theme.getColor("toolbar.button.pressed.field"), + secondary = theme.getColor("editor.gradient.bottom"), + secondaryVariant = theme.getColor("editor.scrollbar.thumb.pressed.color"), + background = theme.getColor("editor.bgcolor"), + surface = theme.getColor("editor.bgcolor"), + error = theme.getColor("status.error.bgcolor"), + onPrimary = theme.getColor("toolbar.button.enabled.field"), + onSecondary = theme.getColor("toolbar.button.enabled.field"), + onBackground = theme.getColor("editor.fgcolor"), + onSurface = theme.getColor("editor.fgcolor"), + onError = theme.getColor("status.error.fgcolor"), + isLight = theme.getProperty("laf.mode").equals("light") + ) + + CompositionLocalProvider(LocalTheme provides theme) { + LocaleProvider { + MaterialTheme( + colors = colors, + typography = Typography, + content = content + ) + } + } + } +} + +fun String.toColorInt(): Int { + if (this[0] == '#') { + var color = substring(1).toLong(16) + if (length == 7) { + color = color or 0x00000000ff000000L + } else if (length != 9) { + throw IllegalArgumentException("Unknown color") + } + return color.toInt() + } + throw IllegalArgumentException("Unknown color") +} \ No newline at end of file diff --git a/app/src/processing/app/ui/theme/Typography.kt b/app/src/processing/app/ui/theme/Typography.kt new file mode 100644 index 000000000..5d87c490e --- /dev/null +++ b/app/src/processing/app/ui/theme/Typography.kt @@ -0,0 +1,38 @@ +package processing.app.ui.theme + +import androidx.compose.material.MaterialTheme.typography +import androidx.compose.material.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.platform.Font +import androidx.compose.ui.unit.sp + +val processingFont = FontFamily( + Font( + resource = "ProcessingSans-Regular.ttf", + weight = FontWeight.Normal, + style = FontStyle.Normal + ), + Font( + resource = "ProcessingSans-Bold.ttf", + weight = FontWeight.Bold, + style = FontStyle.Normal + ) +) + +val Typography = Typography( + body1 = TextStyle( + fontFamily = processingFont, + fontWeight = FontWeight.Normal, + fontSize = 13.sp, + lineHeight = 16.sp + ), + subtitle1 = TextStyle( + fontFamily = processingFont, + fontWeight = FontWeight.Bold, + fontSize = 16.sp, + lineHeight = 20.sp + ) +) \ No newline at end of file diff --git a/build/shared/lib/languages/PDE.properties b/build/shared/lib/languages/PDE.properties index 02f98473e..30446ecd1 100644 --- a/build/shared/lib/languages/PDE.properties +++ b/build/shared/lib/languages/PDE.properties @@ -613,7 +613,6 @@ update_check = Update update_check.updates_available.core = A new version of Processing is available,\nwould you like to visit the Processing download page? update_check.updates_available.contributions = There are updates available for some of the installed contributions,\nwould you like to open the the Contribution Manager now? - # --------------------------------------- # Color Chooser diff --git a/build/shared/lib/languages/PDE_nl.properties b/build/shared/lib/languages/PDE_nl.properties index 9b9527517..f1ac08b5e 100644 --- a/build/shared/lib/languages/PDE_nl.properties +++ b/build/shared/lib/languages/PDE_nl.properties @@ -315,6 +315,13 @@ update_check = Update update_check.updates_available.core = Een nieuwe versie van Processing is beschikbaar,\nwilt u de Processing download pagina bezoeken? update_check.updates_available.contributions = Er zijn updates beschikbaar voor sommige van de door u geïnstalleerde bijdragen,\nwilt u nu de Bijdragen Manager openen? +# --------------------------------------- +# Beta +beta.window.title = Welkom bij Beta +beta.title = Welkom bij de Processing Beta +beta.message = Bedankt dat je de nieuwe versie van Processing uitprobeert. We zijn je zeer dankbaar!\n\nMeld eventuele bugs alsjeblieft op de forums. +beta.button = Okee! + # --------------------------------------- # Color Chooser diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ccc3a55e6..a9fe0b6e5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -25,6 +25,8 @@ netbeansSwing = { module = "org.netbeans.api:org-netbeans-swing-outline", versio ant = { module = "org.apache.ant:ant", version = "1.10.14" } lsp4j = { module = "org.eclipse.lsp4j:org.eclipse.lsp4j", version = "0.22.0" } jsoup = { module = "org.jsoup:jsoup", version = "1.17.2" } +markdown = { module = "com.mikepenz:multiplatform-markdown-renderer-m2", version = "0.31.0" } +markdownJVM = { module = "com.mikepenz:multiplatform-markdown-renderer-jvm", version = "0.31.0" } [plugins] jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }