Skip to content
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

Create IDEA actions to choose export folder and import files #176

Merged
merged 1 commit into from
Sep 26, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,16 @@ import io.github.composegears.valkyrie.ui.ValkyriePlugin
import io.github.composegears.valkyrie.ui.di.Koin
import io.github.composegears.valkyrie.ui.foundation.theme.ValkyrieTheme

class AppToolWindowFactory :
class ValkyrieToolWindow :
ToolWindowFactory,
DumbAware {

init {
Koin.start()
}

override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
System.setProperty("compose.swing.render.on.graphics", "true")
System.setProperty("compose.interop.blending", "true")

Koin.start(project)

toolWindow.addComposePanel {
ValkyrieTheme(
project = project,
Expand All @@ -32,6 +30,10 @@ class AppToolWindowFactory :
}
}
}

companion object {
const val ID = "Valkyrie"
}
}

private fun ToolWindow.addComposePanel(
Expand All @@ -41,7 +43,7 @@ private fun ToolWindow.addComposePanel(
) = PluginWindow(content = content)
.also { contentManager.addContent(contentManager.factory.createContent(it, displayName, isLockable)) }

private class PluginWindow(
class PluginWindow(
height: Int = 800,
width: Int = 800,
y: Int = 0,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package io.github.composegears.valkyrie.action

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import io.github.composegears.valkyrie.parser.svgxml.PackageExtractor
import io.github.composegears.valkyrie.service.PersistentSettings.Companion.persistentSettings

class ExportHereAction : AnAction() {

override fun getActionUpdateThread() = ActionUpdateThread.BGT

override fun actionPerformed(event: AnActionEvent) {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return
val project = event.project ?: return

if (file.isDirectory) {
val predictedPackage = PackageExtractor.getFrom(path = file.path)

project.persistentSettings.stateWithNotify {
if (predictedPackage != null) {
packageName = predictedPackage
}
iconPackDestination = file.path
}
}
}

override fun update(event: AnActionEvent) {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE)
event.presentation.isEnabled = file?.isDirectory == true && event.project != null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.github.composegears.valkyrie.action

import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.wm.ToolWindowManager
import io.github.composegears.valkyrie.ValkyrieToolWindow
import io.github.composegears.valkyrie.action.dialog.RequiredIconPackModeDialog
import io.github.composegears.valkyrie.parser.svgxml.util.isSvg
import io.github.composegears.valkyrie.parser.svgxml.util.isXml
import io.github.composegears.valkyrie.service.GlobalEventsHandler.Companion.globalEventsHandler
import io.github.composegears.valkyrie.service.GlobalEventsHandler.PluginEvents.ImportIcons
import io.github.composegears.valkyrie.service.PersistentSettings.Companion.persistentSettings
import io.github.composegears.valkyrie.ui.domain.model.Mode

class ImportFromDirectoryOrFileAction : AnAction() {

override fun getActionUpdateThread() = ActionUpdateThread.BGT

override fun actionPerformed(event: AnActionEvent) {
val project = event.project ?: return

val toolWindow = ToolWindowManager
.getInstance(project)
.getToolWindow(ValkyrieToolWindow.ID) ?: return

val files = event
.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)
?.filterNotNull() ?: return

val settings = project.persistentSettings.state
val eventsHandler = project.globalEventsHandler

if (settings.mode == Mode.Unspecified.name || settings.mode == Mode.Simple.name) {
RequiredIconPackModeDialog(onOk = toolWindow::show).showAndGet()
} else {
toolWindow.show()
eventsHandler.send(ImportIcons(paths = files.map(VirtualFile::toNioPath)))
}
}

override fun update(event: AnActionEvent) {
val files = event
.getData(CommonDataKeys.VIRTUAL_FILE_ARRAY)
?.filterNotNull()

if (files.isNullOrEmpty() || event.project == null) {
event.presentation.isVisible = false
} else {
if (files.size == 1) {
val file = files.first()

when {
file.isDirectory -> event.presentation.text = "Import All"
else -> event.presentation.text = "Import Icon"
}
event.presentation.isEnabled = when {
file.isDirectory -> file.children.any { it.extension.isXml || it.extension.isSvg }
else -> file.extension.isXml || file.extension.isSvg
}
} else {
event.presentation.text = "Import All"
event.presentation.isEnabled = files.all { it.extension.isXml || it.extension.isSvg }
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package io.github.composegears.valkyrie.action.dialog

import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.intellij.openapi.ui.DialogWrapper
import io.github.composegears.valkyrie.PluginWindow
import io.github.composegears.valkyrie.ui.foundation.theme.ValkyrieTheme

class RequiredIconPackModeDialog(
private val onOk: () -> Unit,
) : DialogWrapper(true) {
init {
title = "Valkyrie Warning"
init()
}

override fun createCenterPanel() = PluginWindow {
ValkyrieTheme {
Text(
modifier = Modifier
.padding(vertical = 16.dp),
style = MaterialTheme.typography.bodySmall,
text = "Please setup IconPack mode before using this feature.",
)
}
}

override fun doOKAction() {
super.doOKAction()
onOk()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import com.intellij.openapi.fileEditor.impl.text.QuickDefinitionProvider
import com.intellij.openapi.project.DumbAware
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import io.github.composegears.valkyrie.settings.PersistentSettings
import io.github.composegears.valkyrie.service.PersistentSettings.Companion.persistentSettings

class ImageVectorPreviewEditorProvider :
FileEditorProvider,
Expand All @@ -18,7 +18,7 @@ class ImageVectorPreviewEditorProvider :
override fun getPolicy(): FileEditorPolicy = FileEditorPolicy.HIDE_DEFAULT_EDITOR

override fun accept(project: Project, file: VirtualFile): Boolean {
val showImageVectorPreview = PersistentSettings.persistentSettings.showImageVectorPreview
val showImageVectorPreview = project.persistentSettings.state.showImageVectorPreview

if (file.extension != "kt" || !showImageVectorPreview) return false

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.composegears.valkyrie.service

import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import java.nio.file.Path
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow

class GlobalEventsHandler {

private val _events = MutableSharedFlow<PluginEvents>(replay = 1)
val events = _events.asSharedFlow()

fun send(event: PluginEvents) {
_events.tryEmit(event)
}

sealed interface PluginEvents {
data class ImportIcons(val paths: List<Path>) : PluginEvents
}

companion object {
@JvmStatic
val Project.globalEventsHandler: GlobalEventsHandler
get() = service<GlobalEventsHandler>()
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
package io.github.composegears.valkyrie.settings
package io.github.composegears.valkyrie.service

import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.SimplePersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.openapi.components.service
import io.github.composegears.valkyrie.settings.PersistentSettings.ValkyrieState
import com.intellij.openapi.project.Project
import io.github.composegears.valkyrie.service.PersistentSettings.ValkyrieState
import io.github.composegears.valkyrie.ui.domain.model.Mode

@Service
@State(name = "Valkyrie.Settings", storages = [Storage("valkyrie_settings.xml")])
class PersistentSettings : SimplePersistentStateComponent<ValkyrieState>(ValkyrieState()) {

private val listeners = mutableListOf<() -> Unit>()

fun addListener(listener: () -> Unit) {
listeners += listener
}

private fun notifyListeners() = listeners.forEach { it() }

fun stateWithNotify(action: ValkyrieState.() -> Unit) {
state.action()
notifyListeners()
}

class ValkyrieState : BaseState() {
var mode: String? by string(Mode.Unspecified.name)

Expand All @@ -30,7 +42,7 @@ class PersistentSettings : SimplePersistentStateComponent<ValkyrieState>(Valkyri

companion object {
@JvmStatic
val persistentSettings: ValkyrieState
get() = service<PersistentSettings>().state
val Project.persistentSettings: PersistentSettings
get() = service<PersistentSettings>()
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,36 @@
package io.github.composegears.valkyrie.settings

import com.intellij.openapi.project.Project
import io.github.composegears.valkyrie.generator.imagevector.OutputFormat
import io.github.composegears.valkyrie.service.PersistentSettings
import io.github.composegears.valkyrie.service.PersistentSettings.Companion.persistentSettings
import io.github.composegears.valkyrie.ui.domain.model.Mode
import io.github.composegears.valkyrie.ui.extension.or
import io.github.composegears.valkyrie.ui.extension.updateState
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow

class InMemorySettings {
private val _settings = MutableStateFlow(value = PersistentSettings.persistentSettings.toValkyriesSettings())
class InMemorySettings(project: Project) {
private val persistentSettings = project.persistentSettings

init {
persistentSettings.addListener {
_settings.updateState { persistentSettings.state.toValkyriesSettings() }
}
}

private val _settings = MutableStateFlow(persistentSettings.state.toValkyriesSettings())
val settings = _settings.asStateFlow()

var uiState: Map<String, Any?> = emptyMap()
private set

val current: ValkyriesSettings
get() = settings.value
get() = _settings.value

fun update(action: PersistentSettings.ValkyrieState.() -> Unit) {
action(PersistentSettings.persistentSettings)
_settings.updateState { PersistentSettings.persistentSettings.toValkyriesSettings() }
action(persistentSettings.state)
_settings.updateState { persistentSettings.state.toValkyriesSettings() }
}

fun clear() = update {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,34 @@ package io.github.composegears.valkyrie.ui
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Modifier
import com.composegears.tiamat.Navigation
import com.composegears.tiamat.rememberNavController
import io.github.composegears.valkyrie.service.GlobalEventsHandler.Companion.globalEventsHandler
import io.github.composegears.valkyrie.service.GlobalEventsHandler.PluginEvents
import io.github.composegears.valkyrie.settings.InMemorySettings
import io.github.composegears.valkyrie.ui.domain.model.Mode.IconPack
import io.github.composegears.valkyrie.ui.domain.model.Mode.Simple
import io.github.composegears.valkyrie.ui.domain.model.Mode.Unspecified
import io.github.composegears.valkyrie.ui.foundation.theme.LocalProject
import io.github.composegears.valkyrie.ui.screen.intro.IntroScreen
import io.github.composegears.valkyrie.ui.screen.mode.iconpack.conversion.IconPackConversionScreen
import io.github.composegears.valkyrie.ui.screen.mode.iconpack.creation.IconPackCreationScreen
import io.github.composegears.valkyrie.ui.screen.mode.simple.conversion.SimpleConversionScreen
import io.github.composegears.valkyrie.ui.screen.mode.simple.setup.SimpleModeSetupScreen
import io.github.composegears.valkyrie.ui.screen.preview.CodePreviewScreen
import io.github.composegears.valkyrie.ui.screen.settings.SettingsScreen
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.koin.compose.koinInject

@Composable
fun ValkyriePlugin(
modifier: Modifier = Modifier,
) {
val inMemorySettings = koinInject<InMemorySettings>()
val project = LocalProject.current

val navController = rememberNavController(
destinations = arrayOf(
Expand Down Expand Up @@ -63,6 +70,26 @@ fun ValkyriePlugin(
},
)

LaunchedEffect(Unit) {
project.globalEventsHandler
.events
.onEach { event ->
when (event) {
is PluginEvents.ImportIcons -> {
navController.editBackStack {
clear()
add(IntroScreen)
}
navController.replace(
dest = IconPackConversionScreen,
navArgs = event.paths,
)
}
}
}
.launchIn(this)
}

DisposableEffect(Unit) {
onDispose {
inMemorySettings.updateUIState(navController.getSavedState())
Expand Down
Loading