Compare commits

..

No commits in common. "6ebdf4051c4869f8340ce476c871ea2bd4523888" and "46af4db9f19e3f5cc84de6f81a8c62a0c52b6aaf" have entirely different histories.

13 changed files with 169 additions and 234 deletions

View File

@ -2,10 +2,10 @@ package com.marvinelsen.willow
import com.marvinelsen.willow.domain.SearchMode import com.marvinelsen.willow.domain.SearchMode
import com.marvinelsen.willow.ui.DictionaryEntryFx import com.marvinelsen.willow.ui.DictionaryEntryFx
import com.marvinelsen.willow.ui.services.FindCharacterService
import com.marvinelsen.willow.ui.services.FindWordsService
import com.marvinelsen.willow.ui.services.SearchService
import com.marvinelsen.willow.ui.util.ClipboardHelper import com.marvinelsen.willow.ui.util.ClipboardHelper
import com.marvinelsen.willow.ui.util.FindCharacterService
import com.marvinelsen.willow.ui.util.FindWordsService
import com.marvinelsen.willow.ui.util.SearchService
import javafx.beans.property.ObjectProperty import javafx.beans.property.ObjectProperty
import javafx.beans.property.ReadOnlyBooleanProperty import javafx.beans.property.ReadOnlyBooleanProperty
import javafx.beans.property.ReadOnlyObjectProperty import javafx.beans.property.ReadOnlyObjectProperty

View File

@ -7,9 +7,9 @@ import com.marvinelsen.willow.ui.controllers.MainController
import com.marvinelsen.willow.ui.controllers.MenuController import com.marvinelsen.willow.ui.controllers.MenuController
import com.marvinelsen.willow.ui.controllers.SearchController import com.marvinelsen.willow.ui.controllers.SearchController
import com.marvinelsen.willow.ui.controllers.SearchResultsController import com.marvinelsen.willow.ui.controllers.SearchResultsController
import com.marvinelsen.willow.ui.services.FindCharacterService import com.marvinelsen.willow.ui.util.FindCharacterService
import com.marvinelsen.willow.ui.services.FindWordsService import com.marvinelsen.willow.ui.util.FindWordsService
import com.marvinelsen.willow.ui.services.SearchService import com.marvinelsen.willow.ui.util.SearchService
import javafx.application.Application import javafx.application.Application
import javafx.fxml.FXMLLoader import javafx.fxml.FXMLLoader
import javafx.scene.Scene import javafx.scene.Scene
@ -66,7 +66,6 @@ class WillowApplication : Application() {
val root = fxmlLoader.load(javaClass.getResourceAsStream("/fxml/main.fxml")) as BorderPane val root = fxmlLoader.load(javaClass.getResourceAsStream("/fxml/main.fxml")) as BorderPane
val primaryScene = Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT) val primaryScene = Scene(root, WINDOW_WIDTH, WINDOW_HEIGHT)
// primaryScene.stylesheets.add(javaClass.getResource("/css/dark.css")?.toExternalForm()!!)
primaryStage.apply { primaryStage.apply {
title = WINDOW_TITLE title = WINDOW_TITLE

View File

@ -8,13 +8,9 @@ import javafx.beans.binding.Bindings
import javafx.fxml.FXML import javafx.fxml.FXML
import javafx.scene.control.MenuBar import javafx.scene.control.MenuBar
import javafx.scene.control.MenuItem import javafx.scene.control.MenuItem
import java.util.ResourceBundle
@Suppress("UnusedPrivateMember") @Suppress("UnusedPrivateMember")
class MenuController(private val model: Model, private val config: Config) { class MenuController(private val model: Model, private val config: Config) {
@FXML
private lateinit var resources: ResourceBundle
@FXML @FXML
private lateinit var menuBar: MenuBar private lateinit var menuBar: MenuBar
@ -32,10 +28,10 @@ class MenuController(private val model: Model, private val config: Config) {
@FXML @FXML
private fun onMenuItemPreferencesAction() { private fun onMenuItemPreferencesAction() {
PreferencesDialog(menuBar.scene.window, config, resources).showAndWait().ifPresent { result -> PreferencesDialog(menuBar.scene.window, config).showAndWait().ifPresent { result ->
when (result) { when (result) {
PreferencesDialog.Result.SAVE_CHANGES -> config.save() PreferencesDialog.Result.CHANGES -> config.save()
PreferencesDialog.Result.DO_NOT_SAVE_CHANGES -> config.load() PreferencesDialog.Result.NO_CHANGES -> config.load()
} }
} }
} }

View File

@ -1,108 +0,0 @@
package com.marvinelsen.willow.ui.controllers.dialogs
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.config.Pronunciation
import com.marvinelsen.willow.config.Script
import com.marvinelsen.willow.config.Theme
import com.marvinelsen.willow.ui.formatters.FontSizeTextFormatter
import javafx.fxml.FXML
import javafx.scene.control.CheckBox
import javafx.scene.control.ComboBox
import javafx.scene.control.Spinner
import java.util.Locale
@Suppress("UnusedPrivateMember")
class PreferencesDialogController(private val config: Config) {
@FXML
private lateinit var comboBoxLocale: ComboBox<Locale>
@FXML
private lateinit var comboBoxTheme: ComboBox<Theme>
@FXML
private lateinit var comboBoxScript: ComboBox<Script>
@FXML
private lateinit var comboBoxPronunciationSearchResults: ComboBox<Pronunciation>
@FXML
private lateinit var comboBoxPronunciationDetails: ComboBox<Pronunciation>
@FXML
private lateinit var checkBoxShowPronunciationSearchResults: CheckBox
@FXML
private lateinit var checkBoxShowDefinitionSearchResults: CheckBox
@FXML
private lateinit var spinnerHeadwordFontSizeDetails: Spinner<Int>
@FXML
private lateinit var spinnerPronunciationFontSizeDetails: Spinner<Int>
@FXML
private lateinit var spinnerHeadwordFontSizeSearchResults: Spinner<Int>
@FXML
private lateinit var spinnerPronunciationFontSizeSearchResults: Spinner<Int>
@FXML
private lateinit var spinnerDefinitionFontSizeSearchResults: Spinner<Int>
private val entryHeadwordFontSizeObjectProperty = config.details.headwordFontSize.asObject()
private val entryPronunciationFontSizeObjectProperty = config.details.pronunciationFontSize.asObject()
private val searchResultHeadwordFontSizeObjectProperty = config.searchResults.headwordFontSize.asObject()
private val searchResultPronunciationFontSizeObjectProperty = config.searchResults.pronunciationFontSize.asObject()
private val searchResultDefinitionFontSizeObjectProperty = config.searchResults.definitionFontSize.asObject()
@FXML
private fun initialize() {
comboBoxLocale.items.addAll(
setOf(
Locale.ENGLISH,
Locale.GERMAN,
Locale.CHINA,
Locale.TAIWAN
)
)
comboBoxTheme.valueProperty().bindBidirectional(config.theme)
comboBoxScript.valueProperty().bindBidirectional(config.script)
comboBoxLocale.valueProperty().bindBidirectional(config.locale)
comboBoxPronunciationSearchResults.valueProperty().bindBidirectional(config.searchResults.pronunciation)
comboBoxPronunciationDetails.valueProperty().bindBidirectional(config.details.pronunciation)
checkBoxShowDefinitionSearchResults
.selectedProperty()
.bindBidirectional(config.searchResults.shouldShowDefinition)
checkBoxShowPronunciationSearchResults
.selectedProperty()
.bindBidirectional(config.searchResults.shouldShowPronunciation)
with(spinnerHeadwordFontSizeDetails) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(entryHeadwordFontSizeObjectProperty)
}
with(spinnerPronunciationFontSizeDetails) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(entryPronunciationFontSizeObjectProperty)
}
with(spinnerHeadwordFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultHeadwordFontSizeObjectProperty)
}
with(spinnerPronunciationFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultPronunciationFontSizeObjectProperty)
}
with(spinnerDefinitionFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultDefinitionFontSizeObjectProperty)
}
}
}

View File

@ -1,42 +1,82 @@
package com.marvinelsen.willow.ui.dialogs package com.marvinelsen.willow.ui.dialogs
import com.marvinelsen.willow.WillowApplication
import com.marvinelsen.willow.config.Config import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.ui.controllers.dialogs.PreferencesDialogController import com.marvinelsen.willow.config.Pronunciation
import com.marvinelsen.willow.config.Script
import com.marvinelsen.willow.config.Theme
import com.marvinelsen.willow.ui.formatters.FontSizeTextFormatter
import javafx.fxml.FXML
import javafx.fxml.FXMLLoader import javafx.fxml.FXMLLoader
import javafx.scene.control.ButtonType import javafx.scene.control.ButtonType
import javafx.scene.control.CheckBox
import javafx.scene.control.ComboBox
import javafx.scene.control.Dialog import javafx.scene.control.Dialog
import javafx.scene.control.DialogPane import javafx.scene.control.DialogPane
import javafx.scene.control.Spinner
import javafx.stage.Modality import javafx.stage.Modality
import javafx.stage.Stage import javafx.stage.Stage
import javafx.stage.Window import javafx.stage.Window
import javafx.util.Callback import javafx.util.Callback
import java.util.ResourceBundle import java.util.Locale
class PreferencesDialog( class PreferencesDialog(owner: Window?, config: Config) : Dialog<PreferencesDialog.Result>() {
owner: Window?,
config: Config,
resources: ResourceBundle,
) : Dialog<PreferencesDialog.Result>() {
companion object { companion object {
private const val MIN_HEIGHT = 400.0 private const val DIALOG_MIN_HEIGHT = 400.0
private const val MIN_WIDTH = 400.0 private const val DIALOG_MIN_WIDTH = 400.0
} }
enum class Result { enum class Result {
SAVE_CHANGES, DO_NOT_SAVE_CHANGES CHANGES, NO_CHANGES
} }
init { @FXML
val fxmlLoader = FXMLLoader() private lateinit var comboBoxLocale: ComboBox<Locale>
fxmlLoader.resources = resources
fxmlLoader.controllerFactory = Callback { type ->
when (type) {
PreferencesDialogController::class.java -> PreferencesDialogController(config)
else -> error("Trying to instantiate unknown controller type $type")
}
}
val root = fxmlLoader.load(javaClass.getResourceAsStream("/fxml/dialogs/preferences.fxml")) as DialogPane @FXML
private lateinit var comboBoxTheme: ComboBox<Theme>
@FXML
private lateinit var comboBoxScript: ComboBox<Script>
@FXML
private lateinit var comboBoxPronunciationSearchResults: ComboBox<Pronunciation>
@FXML
private lateinit var comboBoxPronunciationDetails: ComboBox<Pronunciation>
@FXML
private lateinit var checkBoxShowPronunciationSearchResults: CheckBox
@FXML
private lateinit var checkBoxShowDefinitionSearchResults: CheckBox
@FXML
private lateinit var spinnerHeadwordFontSizeDetails: Spinner<Int>
@FXML
private lateinit var spinnerPronunciationFontSizeDetails: Spinner<Int>
@FXML
private lateinit var spinnerHeadwordFontSizeSearchResults: Spinner<Int>
@FXML
private lateinit var spinnerPronunciationFontSizeSearchResults: Spinner<Int>
@FXML
private lateinit var spinnerDefinitionFontSizeSearchResults: Spinner<Int>
private val entryHeadwordFontSizeObjectProperty = config.details.headwordFontSize.asObject()
private val entryPronunciationFontSizeObjectProperty = config.details.pronunciationFontSize.asObject()
private val searchResultHeadwordFontSizeObjectProperty = config.searchResults.headwordFontSize.asObject()
private val searchResultPronunciationFontSizeObjectProperty = config.searchResults.pronunciationFontSize.asObject()
private val searchResultDefinitionFontSizeObjectProperty = config.searchResults.definitionFontSize.asObject()
init {
val loader = FXMLLoader(WillowApplication::class.java.getResource("/fxml/dialogs/preferences.fxml"))
loader.setController(this)
val root: DialogPane = loader.load()
dialogPane = root dialogPane = root
title = "Settings" title = "Settings"
@ -46,8 +86,55 @@ class PreferencesDialog(
initModality(Modality.APPLICATION_MODAL) initModality(Modality.APPLICATION_MODAL)
(dialogPane.scene.window as Stage).apply { (dialogPane.scene.window as Stage).apply {
minWidth = MIN_WIDTH minWidth = DIALOG_MIN_WIDTH
minHeight = MIN_HEIGHT minHeight = DIALOG_MIN_HEIGHT
}
comboBoxLocale.items.addAll(
setOf(
Locale.ENGLISH,
Locale.GERMAN,
Locale.CHINA,
Locale.TAIWAN
)
)
comboBoxTheme.valueProperty().bindBidirectional(config.theme)
comboBoxScript.valueProperty().bindBidirectional(config.script)
comboBoxLocale.valueProperty().bindBidirectional(config.locale)
comboBoxPronunciationSearchResults.valueProperty().bindBidirectional(config.searchResults.pronunciation)
comboBoxPronunciationDetails.valueProperty().bindBidirectional(config.details.pronunciation)
checkBoxShowDefinitionSearchResults
.selectedProperty()
.bindBidirectional(config.searchResults.shouldShowDefinition)
checkBoxShowPronunciationSearchResults
.selectedProperty()
.bindBidirectional(config.searchResults.shouldShowPronunciation)
with(spinnerHeadwordFontSizeDetails) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(entryHeadwordFontSizeObjectProperty)
}
with(spinnerPronunciationFontSizeDetails) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(entryPronunciationFontSizeObjectProperty)
}
with(spinnerHeadwordFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultHeadwordFontSizeObjectProperty)
}
with(spinnerPronunciationFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultPronunciationFontSizeObjectProperty)
}
with(spinnerDefinitionFontSizeSearchResults) {
editor.textFormatter = FontSizeTextFormatter()
valueFactory.valueProperty().bindBidirectional(searchResultDefinitionFontSizeObjectProperty)
} }
resultConverter = Callback(::convertToResult) resultConverter = Callback(::convertToResult)
@ -55,7 +142,7 @@ class PreferencesDialog(
private fun convertToResult(buttonType: ButtonType) = private fun convertToResult(buttonType: ButtonType) =
when (buttonType) { when (buttonType) {
ButtonType.APPLY -> Result.SAVE_CHANGES ButtonType.APPLY -> Result.CHANGES
else -> Result.DO_NOT_SAVE_CHANGES else -> Result.NO_CHANGES
} }
} }

View File

@ -1,20 +0,0 @@
package com.marvinelsen.willow.ui.services
import com.marvinelsen.willow.domain.Dictionary
import com.marvinelsen.willow.ui.DictionaryEntryFx
import com.marvinelsen.willow.ui.toDomain
import com.marvinelsen.willow.ui.toFx
import com.marvinelsen.willow.ui.util.task
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.concurrent.Service
class FindCharacterService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var entry: DictionaryEntryFx
override fun createTask() = task {
if (!this::entry.isInitialized) error("Entry is not initialized")
FXCollections.observableList(dictionary.findCharacters(entry.toDomain()).map { it.toFx() })
}
}

View File

@ -1,20 +0,0 @@
package com.marvinelsen.willow.ui.services
import com.marvinelsen.willow.domain.Dictionary
import com.marvinelsen.willow.ui.DictionaryEntryFx
import com.marvinelsen.willow.ui.toDomain
import com.marvinelsen.willow.ui.toFx
import com.marvinelsen.willow.ui.util.task
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.concurrent.Service
class FindWordsService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var entry: DictionaryEntryFx
override fun createTask() = task {
if (!this::entry.isInitialized) error("Entry is not initialized")
FXCollections.observableList(dictionary.findWordsContaining(entry.toDomain()).map { it.toFx() })
}
}

View File

@ -1,22 +0,0 @@
package com.marvinelsen.willow.ui.services
import com.marvinelsen.willow.domain.Dictionary
import com.marvinelsen.willow.domain.SearchMode
import com.marvinelsen.willow.ui.DictionaryEntryFx
import com.marvinelsen.willow.ui.toFx
import com.marvinelsen.willow.ui.util.task
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.concurrent.Service
class SearchService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var searchQuery: String
lateinit var searchMode: SearchMode
override fun createTask() = task {
if (!this::searchQuery.isInitialized) error("Search query is not initialized")
if (!this::searchMode.isInitialized) error("Search mode is not initialized")
FXCollections.observableList(dictionary.search(searchQuery, searchMode).map { it.toFx() })
}
}

View File

@ -0,0 +1,42 @@
package com.marvinelsen.willow.ui.util
import com.marvinelsen.willow.domain.Dictionary
import com.marvinelsen.willow.domain.SearchMode
import com.marvinelsen.willow.ui.DictionaryEntryFx
import com.marvinelsen.willow.ui.toDomain
import com.marvinelsen.willow.ui.toFx
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import javafx.concurrent.Service
class SearchService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var searchQuery: String
lateinit var searchMode: SearchMode
override fun createTask() = task {
if (!this::searchQuery.isInitialized) error("Search query is not initialized")
if (!this::searchMode.isInitialized) error("Search mode is not initialized")
FXCollections.observableList(dictionary.search(searchQuery, searchMode).map { it.toFx() })
}
}
class FindWordsService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var entry: DictionaryEntryFx
override fun createTask() = task {
if (!this::entry.isInitialized) error("Entry is not initialized")
FXCollections.observableList(dictionary.findWordsContaining(entry.toDomain()).map { it.toFx() })
}
}
class FindCharacterService(private val dictionary: Dictionary) : Service<ObservableList<DictionaryEntryFx>>() {
lateinit var entry: DictionaryEntryFx
override fun createTask() = task {
if (!this::entry.isInitialized) error("Entry is not initialized")
FXCollections.observableList(dictionary.findCharacters(entry.toDomain()).map { it.toFx() })
}
}

View File

@ -4,21 +4,13 @@ https://openjfx.io/javadoc/23/javafx.graphics/javafx/scene/doc-files/cssref.html
*/ */
.root { .root {
willow-background: #282828; willow-background: #2D2D30;
willow-foreground: #dfdfdf; willow-foreground: #ffffff;
-fx-base: willow-background;
-fx-accent: #5c7654;
-fx-focus-color: #3e8f25;
-fx-background-color: willow-background; -fx-background-color: willow-background;
-fx-text-fill: willow-foreground; background-color: willow-background;
} }
/*.split-pane {
-fx-background-color: willow-background;
}*/
.label { .label {
-fx-text-fill: willow-foreground; -fx-text-fill: willow-foreground;
} }
@ -26,13 +18,3 @@ https://openjfx.io/javadoc/23/javafx.graphics/javafx/scene/doc-files/cssref.html
.radio-button { .radio-button {
-fx-text-fill: willow-foreground; -fx-text-fill: willow-foreground;
} }
.list-cell:even {
-fx-text-fill: willow-foreground;
-fx-background: #1e1e1e;
}
.list-cell:odd {
-fx-text-fill: willow-foreground;
-fx-background: #292929;
}

View File

@ -7,7 +7,7 @@
<VBox xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1" <VBox xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.marvinelsen.willow.ui.controllers.DetailsController" fx:controller="com.marvinelsen.willow.ui.controllers.DetailsController"
stylesheets="/css/details.css"> stylesheets="/css/details.css">
<FlowPane fx:id="flowPaneHeader" styleClass="flow-pane-header" hgap="8.0" onContextMenuRequested="#headerOnContextMenuRequested" <FlowPane fx:id="flowPaneHeader" hgap="8.0" onContextMenuRequested="#headerOnContextMenuRequested"
prefHeight="38.0" prefWidth="412.0" rowValignment="BASELINE" vgap="8.0" VBox.vgrow="NEVER"> prefHeight="38.0" prefWidth="412.0" rowValignment="BASELINE" vgap="8.0" VBox.vgrow="NEVER">
<padding> <padding>
<Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/> <Insets bottom="6.0" left="6.0" right="6.0" top="6.0"/>

View File

@ -7,8 +7,7 @@
<?import javafx.scene.control.*?> <?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?> <?import javafx.scene.layout.*?>
<DialogPane styleClass="preferences-dialog" xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1" <DialogPane styleClass="preferences-dialog" xmlns="http://javafx.com/javafx/23" xmlns:fx="http://javafx.com/fxml/1"
stylesheets="/css/preferences.css" stylesheets="/css/preferences.css">
fx:controller="com.marvinelsen.willow.ui.controllers.dialogs.PreferencesDialogController">
<fx:define> <fx:define>
<FXCollections fx:factory="observableArrayList" fx:id="phoneticAlphabets"> <FXCollections fx:factory="observableArrayList" fx:id="phoneticAlphabets">
<Pronunciation fx:value="PINYIN_WITH_TONE_MARKS"/> <Pronunciation fx:value="PINYIN_WITH_TONE_MARKS"/>
@ -170,6 +169,6 @@
</Tab> </Tab>
</TabPane> </TabPane>
</content> </content>
<ButtonType fx:constant="APPLY"/> <ButtonType fx:id="buttonTypeApply" fx:constant="APPLY"/>
<ButtonType fx:constant="CANCEL"/> <ButtonType fx:constant="CANCEL"/>
</DialogPane> </DialogPane>

View File

@ -15,7 +15,7 @@
<Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/> <Insets bottom="8.0" left="8.0" right="8.0" top="8.0"/>
</BorderPane.margin> </BorderPane.margin>
<fx:include source="/fxml/search.fxml"/> <fx:include source="/fxml/search.fxml"/>
<SplitPane styleClass="split-pane" dividerPositions="0.33" VBox.vgrow="ALWAYS"> <SplitPane dividerPositions="0.33" VBox.vgrow="ALWAYS">
<fx:include source="/fxml/search-results.fxml"/> <fx:include source="/fxml/search-results.fxml"/>
<fx:include source="/fxml/details.fxml"/> <fx:include source="/fxml/details.fxml"/>
</SplitPane> </SplitPane>