New Features #1

Open
marvinelsen wants to merge 95 commits from develop into main
19 changed files with 348 additions and 269 deletions
Showing only changes of commit a2dfc858f4 - Show all commits

View File

@ -0,0 +1,127 @@
package com.marvinelsen.willow
import com.marvinelsen.willow.domain.SearchMode
import com.marvinelsen.willow.domain.SqliteDictionary
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.ui.undo.Command
import com.marvinelsen.willow.ui.util.ClipboardHelper
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
@Suppress("TooManyFunctions")
class Interactor(
private val model: Model,
private val dictionary: SqliteDictionary,
) {
private val coroutineScope = MainScope()
fun copyHeadwordOfSelectedEntry() {
model.selectedEntry?.let { ClipboardHelper.copyString(it.traditional) }
}
fun copyPronunciationOfSelectedEntry() {
model.selectedEntry?.let { ClipboardHelper.copyString(it.pinyinWithToneMarks) }
}
fun undoSelection() {
model.undoManager.undo()
}
fun redoSelection() {
model.undoManager.redo()
}
fun search(query: String, searchMode: SearchMode) {
coroutineScope.launch {
model.isSearching = true
model.searchResults.setAll(dictionary.search(query, searchMode))
model.isSearching = false
}
}
fun findWordsBeginning() {
coroutineScope.launch {
model.isFindingWordsBeginning = true
model.wordsBeginning.setAll(
model.selectedEntry?.let {
dictionary
.findWordsBeginningWith(it)
}
)
model.isFindingWordsBeginning = false
model.finishedFindingWordsBeginning = true
}
}
fun findWordsContaining() {
coroutineScope.launch {
model.isFindingWordsContaining = true
model.wordsContaining.setAll(
model.selectedEntry?.let {
dictionary
.findWordsContaining(it)
}
)
model.isFindingWordsContaining = false
model.finishedFindingWordsContaining = true
}
}
fun findCharacters() {
coroutineScope.launch {
model.isFindingCharacters = true
model.characters.setAll(
model.selectedEntry?.let {
dictionary
.findCharactersOf(it)
}
)
model.isFindingCharacters = false
model.finishedFindingCharacters = true
}
}
fun findSentences() {
coroutineScope.launch {
model.isFindingSentences = true
model.sentences.setAll(
model.selectedEntry?.let {
dictionary
.findExampleSentencesFor(it)
}
)
model.isFindingSentences = false
model.finishedFindingSentences = true
}
}
fun deepDive(entry: DictionaryEntry) {
model.undoManager.execute(object : Command {
private val previouslySelectedEntry = model.selectedEntry
override fun execute() {
select(entry)
}
override fun undo() {
if (previouslySelectedEntry == null) return
select(previouslySelectedEntry)
}
})
}
fun normalSelect(entry: DictionaryEntry) {
model.undoManager.reset()
select(entry)
}
private fun select(entry: DictionaryEntry) {
model.finishedFindingCharacters = false
model.finishedFindingWordsBeginning = false
model.finishedFindingWordsContaining = false
model.finishedFindingSentences = false
model.selectedEntry = entry
}
}

View File

@ -0,0 +1,110 @@
package com.marvinelsen.willow
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.domain.objects.Sentence
import com.marvinelsen.willow.ui.undo.UndoManager
import javafx.beans.property.BooleanProperty
import javafx.beans.property.ObjectProperty
import javafx.beans.property.ReadOnlyBooleanProperty
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.collections.ObservableList
@Suppress("TooManyFunctions")
class Model(
val undoManager: UndoManager,
) {
private val _selectedEntry: ObjectProperty<DictionaryEntry?> = SimpleObjectProperty<DictionaryEntry>()
private val _isSearching: BooleanProperty = SimpleBooleanProperty(false)
private val _isFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
private val _isFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
private val _isFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
private val _isFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
private val _finishedFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
private val _finishedFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
private val _finishedFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
private val _finishedFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
val searchResults: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
val wordsBeginning: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
val wordsContaining: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
val characters: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
val sentences: ObservableList<Sentence> = FXCollections.observableArrayList()
val canUndo: ReadOnlyBooleanProperty = undoManager.canUndoProperty
val canRedo: ReadOnlyBooleanProperty = undoManager.canRedoProperty
var selectedEntry: DictionaryEntry?
get() = _selectedEntry.value
set(value) {
_selectedEntry.value = value
}
var isSearching: Boolean
get() = _isSearching.value
set(value) {
_isSearching.value = value
}
var isFindingWordsBeginning: Boolean
get() = _isFindingWordsBeginning.value
set(value) {
_isFindingWordsBeginning.value = value
}
var isFindingWordsContaining: Boolean
get() = _isFindingWordsContaining.value
set(value) {
_isFindingWordsContaining.value = value
}
var isFindingCharacters: Boolean
get() = _isFindingCharacters.value
set(value) {
_isFindingCharacters.value = value
}
var isFindingSentences: Boolean
get() = _isFindingSentences.value
set(value) {
_isFindingSentences.value = value
}
var finishedFindingWordsBeginning: Boolean
get() = _finishedFindingWordsBeginning.value
set(value) {
_finishedFindingWordsBeginning.value = value
}
var finishedFindingWordsContaining: Boolean
get() = _finishedFindingWordsContaining.value
set(value) {
_finishedFindingWordsContaining.value = value
}
var finishedFindingCharacters: Boolean
get() = _finishedFindingCharacters.value
set(value) {
_finishedFindingCharacters.value = value
}
var finishedFindingSentences: Boolean
get() = _finishedFindingSentences.value
set(value) {
_finishedFindingSentences.value = value
}
fun selectedEntryProperty(): ObjectProperty<DictionaryEntry?> = _selectedEntry
fun isSearchingProperty(): BooleanProperty = _isSearching
fun isFindingWordsBeginningProperty(): BooleanProperty = _isFindingWordsBeginning
fun isFindingWordsContainingProperty(): BooleanProperty = _isFindingWordsContaining
fun isFindingCharactersProperty(): BooleanProperty = _isFindingCharacters
fun isFindingSentencesProperty(): BooleanProperty = _isFindingSentences
fun finishedFindingWordsBeginning(): BooleanProperty = _finishedFindingWordsBeginning
fun finishedFindingWordsContaining(): BooleanProperty = _finishedFindingWordsContaining
fun finishedFindingCharacters(): BooleanProperty = _finishedFindingCharacters
fun finishedFindingSentences(): BooleanProperty = _finishedFindingSentences
}

View File

@ -1,174 +0,0 @@
package com.marvinelsen.willow
import com.marvinelsen.willow.domain.SearchMode
import com.marvinelsen.willow.domain.SqliteDictionary
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.ui.undo.Command
import com.marvinelsen.willow.ui.undo.UndoManager
import com.marvinelsen.willow.ui.util.ClipboardHelper
import javafx.beans.property.BooleanProperty
import javafx.beans.property.ObjectProperty
import javafx.beans.property.ReadOnlyBooleanProperty
import javafx.beans.property.ReadOnlyObjectProperty
import javafx.beans.property.SimpleBooleanProperty
import javafx.beans.property.SimpleObjectProperty
import javafx.collections.FXCollections
import javafx.collections.ObservableList
import kotlinx.coroutines.MainScope
import kotlinx.coroutines.launch
@Suppress("TooManyFunctions")
class State(
private val dictionary: SqliteDictionary,
private val undoManager: UndoManager,
) {
private val internalSelectedEntry: ObjectProperty<DictionaryEntry> = SimpleObjectProperty()
private val internalSearchResults: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
private val internalWordsBeginning: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
private val internalWordsContaining: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
private val internalCharacters: ObservableList<DictionaryEntry> = FXCollections.observableArrayList()
private val internalSentences: ObservableList<Sentence> = FXCollections.observableArrayList()
private val internalIsSearching: BooleanProperty = SimpleBooleanProperty(false)
private val internalIsFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
private val internalIsFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
private val internalIsFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
private val internalIsFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
private val internalFinishedFindingWordsBeginning: BooleanProperty = SimpleBooleanProperty(false)
private val internalFinishedFindingWordsContaining: BooleanProperty = SimpleBooleanProperty(false)
private val internalFinishedFindingCharacters: BooleanProperty = SimpleBooleanProperty(false)
private val internalFinishedFindingSentences: BooleanProperty = SimpleBooleanProperty(false)
val canUndo: ReadOnlyBooleanProperty = undoManager.canUndoProperty
val canRedo: ReadOnlyBooleanProperty = undoManager.canRedoProperty
val selectedEntry: ReadOnlyObjectProperty<DictionaryEntry> = internalSelectedEntry
val searchResults: ObservableList<DictionaryEntry> =
FXCollections.unmodifiableObservableList(internalSearchResults)
val wordsBeginning: ObservableList<DictionaryEntry> =
FXCollections.unmodifiableObservableList(internalWordsBeginning)
val wordsContaining: ObservableList<DictionaryEntry> =
FXCollections.unmodifiableObservableList(internalWordsContaining)
val characters: ObservableList<DictionaryEntry> =
FXCollections.unmodifiableObservableList(internalCharacters)
val sentences: ObservableList<Sentence> =
FXCollections.unmodifiableObservableList(internalSentences)
val isSearching: ReadOnlyBooleanProperty = internalIsSearching
val isFindingWordsBeginning: ReadOnlyBooleanProperty = internalIsFindingWordsBeginning
val isFindingWordsContaining: ReadOnlyBooleanProperty = internalIsFindingWordsContaining
val isFindingCharacters: ReadOnlyBooleanProperty = internalIsFindingCharacters
val isFindingSentences: ReadOnlyBooleanProperty = internalIsFindingSentences
val finishedFindingWordsBeginning: ReadOnlyBooleanProperty = internalFinishedFindingWordsBeginning
val finishedFindingWordsContaining: ReadOnlyBooleanProperty = internalFinishedFindingWordsContaining
val finishedFindingCharacters: ReadOnlyBooleanProperty = internalFinishedFindingCharacters
val finishedFindingSentences: ReadOnlyBooleanProperty = internalFinishedFindingSentences
private val coroutineScope = MainScope()
fun copyHeadwordOfSelectedEntry() {
ClipboardHelper.copyString(internalSelectedEntry.value.traditional)
}
fun copyPronunciationOfSelectedEntry() {
ClipboardHelper.copyString(internalSelectedEntry.value.pinyinWithToneMarks)
}
fun undoSelection() {
undoManager.undo()
}
fun redoSelection() {
undoManager.redo()
}
fun search(query: String, searchMode: SearchMode) {
coroutineScope.launch {
internalIsSearching.value = true
internalSearchResults.setAll(dictionary.search(query, searchMode))
internalIsSearching.value = false
}
}
fun findWordsBeginning() {
coroutineScope.launch {
internalIsFindingWordsBeginning.value = true
internalWordsBeginning.setAll(
dictionary
.findWordsBeginningWith(internalSelectedEntry.value)
)
internalIsFindingWordsBeginning.value = false
internalFinishedFindingWordsBeginning.value = true
}
}
fun findWordsContaining() {
coroutineScope.launch {
internalIsFindingWordsContaining.value = true
internalWordsContaining.setAll(
dictionary
.findWordsContaining(internalSelectedEntry.value)
)
internalIsFindingWordsContaining.value = false
internalFinishedFindingWordsContaining.value = true
}
}
fun findCharacters() {
coroutineScope.launch {
internalIsFindingCharacters.value = true
internalCharacters.setAll(
dictionary
.findCharactersOf(internalSelectedEntry.value)
)
internalIsFindingCharacters.value = false
internalFinishedFindingCharacters.value = true
}
}
fun findSentences() {
coroutineScope.launch {
internalIsFindingSentences.value = true
internalSentences.setAll(
dictionary
.findExampleSentencesFor(internalSelectedEntry.value)
)
internalIsFindingSentences.value = false
internalFinishedFindingSentences.value = true
}
}
fun deepDive(entry: DictionaryEntry) {
undoManager.execute(object : Command {
private val previouslySelectedEntry = internalSelectedEntry.value
override fun execute() {
select(entry)
}
override fun undo() {
if (previouslySelectedEntry == null) return
select(previouslySelectedEntry)
}
})
}
fun normalSelect(entry: DictionaryEntry) {
undoManager.reset()
select(entry)
}
private fun select(entry: DictionaryEntry) {
internalFinishedFindingCharacters.value = false
internalFinishedFindingWordsBeginning.value = false
internalFinishedFindingWordsContaining.value = false
internalFinishedFindingSentences.value = false
internalSelectedEntry.value = entry
}
}

View File

@ -43,10 +43,8 @@ class WillowApplication : Application() {
}
val dictionary = SqliteDictionary(connection)
val undoManager = UndoManager()
val state = State(
dictionary,
undoManager
)
val model = Model(undoManager)
val interactor = Interactor(model, dictionary)
val config = Config()
config.load()
@ -56,11 +54,11 @@ class WillowApplication : Application() {
fxmlLoader.resources = ResourceBundle.getBundle("i18n/willow", config.locale.value)
fxmlLoader.controllerFactory = Callback { type ->
when (type) {
MainController::class.java -> MainController(state)
MenuController::class.java -> MenuController(state, config)
DetailsController::class.java -> DetailsController(state, config, hostServices)
SearchController::class.java -> SearchController(state)
SearchResultsController::class.java -> SearchResultsController(state, config, hostServices)
MainController::class.java -> MainController(model)
MenuController::class.java -> MenuController(model, interactor, config)
DetailsController::class.java -> DetailsController(model, interactor, config, hostServices)
SearchController::class.java -> SearchController(model, interactor)
SearchResultsController::class.java -> SearchResultsController(model, interactor, config, hostServices)
else -> error("Trying to instantiate unknown controller type $type")
}
}

View File

@ -1,7 +1,7 @@
package com.marvinelsen.willow.domain
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.domain.objects.Sentence
interface Dictionary {
suspend fun search(query: String, searchMode: SearchMode): List<DictionaryEntry>

View File

@ -8,8 +8,8 @@ import com.github.houbb.segment.support.segment.impl.Segments
import com.github.houbb.segment.support.segment.mode.impl.SegmentModes
import com.github.houbb.segment.support.segment.result.impl.SegmentResultHandlers
import com.github.houbb.segment.support.tagging.pos.tag.impl.SegmentPosTaggings
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.domain.objects.Sentence
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json

View File

@ -1,7 +1,7 @@
package com.marvinelsen.willow.domain.entities
package com.marvinelsen.willow.domain.objects
import com.marvinelsen.willow.domain.entities.definitions.CrossStraitsDefinition
import com.marvinelsen.willow.domain.entities.definitions.MoedictDefinition
import com.marvinelsen.willow.domain.objects.definitions.CrossStraitsDefinition
import com.marvinelsen.willow.domain.objects.definitions.MoedictDefinition
data class DictionaryEntry(
val traditional: String,

View File

@ -1,4 +1,4 @@
package com.marvinelsen.willow.domain.entities
package com.marvinelsen.willow.domain.objects
data class Sentence(
val traditional: String,

View File

@ -1,4 +1,4 @@
package com.marvinelsen.willow.domain.entities.definitions
package com.marvinelsen.willow.domain.objects.definitions
import kotlinx.serialization.Serializable

View File

@ -1,4 +1,4 @@
package com.marvinelsen.willow.domain.entities.definitions
package com.marvinelsen.willow.domain.objects.definitions
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

View File

@ -2,7 +2,7 @@ package com.marvinelsen.willow.ui.cells
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.config.Pronunciation
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.ui.components.TextFlowWithToneColors
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
import javafx.application.HostServices

View File

@ -2,7 +2,7 @@ package com.marvinelsen.willow.ui.cells
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.config.Script
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.domain.objects.Sentence
import com.marvinelsen.willow.ui.util.createContextMenuForSentence
import javafx.application.HostServices
import javafx.beans.binding.Bindings

View File

@ -2,7 +2,7 @@ package com.marvinelsen.willow.ui.components
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.config.Script
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import javafx.beans.property.SimpleObjectProperty
import javafx.scene.paint.Color
import javafx.scene.text.Text

View File

@ -1,11 +1,12 @@
package com.marvinelsen.willow.ui.controllers
import com.marvinelsen.willow.State
import com.marvinelsen.willow.Interactor
import com.marvinelsen.willow.Model
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.config.Pronunciation
import com.marvinelsen.willow.config.Script
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.domain.objects.Sentence
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
import com.marvinelsen.willow.ui.cells.SentenceCellFactory
import com.marvinelsen.willow.ui.util.createContextMenuForEntry
@ -33,7 +34,8 @@ import java.util.ResourceBundle
@Suppress("UnusedPrivateMember", "TooManyFunctions")
class DetailsController(
private val state: State,
private val model: Model,
private val interactor: Interactor,
private val config: Config,
private val hostServices: HostServices,
) {
@ -112,14 +114,13 @@ class DetailsController(
textProperty().bind(
Bindings.createStringBinding(
{
val selectedEntry = state.selectedEntry.value
when (config.script.value!!) {
Script.SIMPLIFIED -> selectedEntry?.simplified
Script.TRADITIONAL -> selectedEntry?.traditional
Script.SIMPLIFIED -> model.selectedEntry?.simplified
Script.TRADITIONAL -> model.selectedEntry?.traditional
}
},
config.script,
state.selectedEntry
model.selectedEntryProperty()
)
)
styleProperty().bind(
@ -137,15 +138,14 @@ class DetailsController(
textProperty().bind(
Bindings.createStringBinding(
{
val selectedEntry = state.selectedEntry.value
when (config.details.pronunciation.value!!) {
Pronunciation.PINYIN_WITH_TONE_MARKS -> selectedEntry?.pinyinWithToneMarks
Pronunciation.PINYIN_WITH_TONE_NUMBERS -> selectedEntry?.pinyinWithToneNumbers
Pronunciation.ZHUYIN -> selectedEntry?.zhuyin
Pronunciation.PINYIN_WITH_TONE_MARKS -> model.selectedEntry?.pinyinWithToneMarks
Pronunciation.PINYIN_WITH_TONE_NUMBERS -> model.selectedEntry?.pinyinWithToneNumbers
Pronunciation.ZHUYIN -> model.selectedEntry?.zhuyin
}
},
config.details.pronunciation,
state.selectedEntry
model.selectedEntryProperty()
)
)
styleProperty().bind(
@ -160,16 +160,16 @@ class DetailsController(
private fun initializeTabPaneDetails() {
tabPaneDetails.apply {
disableProperty().bind(Bindings.isNull(state.selectedEntry))
disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
selectionModel.selectedItemProperty().addListener { _, _, selectedTab ->
if (state.selectedEntry.value == null) return@addListener
if (model.selectedEntry == null) return@addListener
lazyUpdateTabContent(selectedTab.id)
}
}
state.selectedEntry.addListener { _, _, newEntry ->
model.selectedEntryProperty().addListener { _, _, newEntry ->
if (newEntry == null) return@addListener
tabPaneDetails.selectionModel.select(0)
@ -178,9 +178,9 @@ class DetailsController(
tabCharacters.disableProperty().bind(
Bindings.createBooleanBinding(
{
(state.selectedEntry.value?.traditional?.length ?: 0) < 2
(model.selectedEntry?.traditional?.length ?: 0) < 2
},
state.selectedEntry
model.selectedEntryProperty()
)
)
}
@ -188,68 +188,82 @@ class DetailsController(
private fun initializeListViewSentences() {
listViewSentences.apply {
cellFactory = SentenceCellFactory(resources, config, hostServices)
items = state.sentences
items = model.sentences
disableProperty().bind(Bindings.or(state.isFindingSentences, Bindings.isEmpty(state.sentences)))
disableProperty().bind(Bindings.or(model.isFindingSentencesProperty(), Bindings.isEmpty(model.sentences)))
}
progressIndicatorSentences.visibleProperty().bind(state.isFindingSentences)
progressIndicatorSentences.visibleProperty().bind(model.isFindingSentencesProperty())
labelNoSentencesFound
.visibleProperty()
.bind(Bindings.and(Bindings.isEmpty(state.sentences), Bindings.not(state.isFindingSentences)))
.bind(Bindings.and(Bindings.isEmpty(model.sentences), Bindings.not(model.isFindingSentencesProperty())))
}
private fun initializeListViewWordsContaining() {
listViewWordsContaining.apply {
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
items = state.wordsContaining
items = model.wordsContaining
disableProperty().bind(Bindings.or(state.isFindingWordsContaining, Bindings.isEmpty(state.wordsContaining)))
disableProperty().bind(
Bindings.or(model.isFindingWordsContainingProperty(), Bindings.isEmpty(model.wordsContaining))
)
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
if (newEntry == null) return@addListener
state.deepDive(newEntry)
interactor.deepDive(newEntry)
}
}
progressIndicatorWordsContaining.visibleProperty().bind(state.isFindingWordsContaining)
progressIndicatorWordsContaining.visibleProperty().bind(model.isFindingWordsContainingProperty())
labelNoWordsContainingFound
.visibleProperty()
.bind(Bindings.and(Bindings.isEmpty(state.wordsContaining), Bindings.not(state.isFindingWordsContaining)))
.bind(
Bindings.and(
Bindings.isEmpty(model.wordsContaining),
Bindings.not(model.isFindingWordsContainingProperty())
)
)
}
private fun initializeListViewWordsBeginning() {
listViewWordsBeginning.apply {
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
items = state.wordsBeginning
items = model.wordsBeginning
disableProperty().bind(Bindings.or(state.isFindingWordsBeginning, Bindings.isEmpty(state.wordsBeginning)))
disableProperty().bind(
Bindings.or(model.isFindingWordsBeginningProperty(), Bindings.isEmpty(model.wordsBeginning))
)
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
if (newEntry == null) return@addListener
state.deepDive(newEntry)
interactor.deepDive(newEntry)
}
}
progressIndicatorWordsBeginning.visibleProperty().bind(state.isFindingWordsBeginning)
progressIndicatorWordsBeginning.visibleProperty().bind(model.isFindingWordsBeginningProperty())
labelNoWordsBeginningFound
.visibleProperty()
.bind(Bindings.and(Bindings.isEmpty(state.wordsBeginning), Bindings.not(state.isFindingWordsBeginning)))
.bind(
Bindings.and(
Bindings.isEmpty(model.wordsBeginning),
Bindings.not(model.isFindingWordsBeginningProperty())
)
)
}
private fun initializeListViewCharacters() {
listViewCharacters.apply {
cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
items = state.characters
items = model.characters
disableProperty().bind(Bindings.or(state.isFindingCharacters, Bindings.isEmpty(state.characters)))
disableProperty().bind(Bindings.or(model.isFindingCharactersProperty(), Bindings.isEmpty(model.characters)))
selectionModel.selectedItemProperty().addListener { _, _, newEntry ->
if (newEntry == null) return@addListener
state.deepDive(newEntry)
interactor.deepDive(newEntry)
}
}
progressIndicatorCharacters.visibleProperty().bind(state.isFindingCharacters)
progressIndicatorCharacters.visibleProperty().bind(model.isFindingCharactersProperty())
labelNoCharactersFound
.visibleProperty()
.bind(Bindings.and(Bindings.isEmpty(state.characters), Bindings.not(state.isFindingCharacters)))
.bind(Bindings.and(Bindings.isEmpty(model.characters), Bindings.not(model.isFindingCharactersProperty())))
}
private fun initializeWebViewDefinition() {
@ -257,7 +271,7 @@ class DetailsController(
engine.userStyleSheetLocation = this::class.java.getResource("/css/definitions.css")!!.toExternalForm()
}
state.selectedEntry.addListener { _, _, newEntry ->
model.selectedEntryProperty().addListener { _, _, newEntry ->
if (newEntry == null) return@addListener
webViewDefinition.engine.loadContent(createDefinitionHtml(newEntry))
@ -266,9 +280,9 @@ class DetailsController(
@FXML
private fun headerOnContextMenuRequested(contextMenuEvent: ContextMenuEvent) {
if (state.selectedEntry.value == null) return
if (model.selectedEntry == null) return
createContextMenuForEntry(state.selectedEntry.value, resources, hostServices).show(
createContextMenuForEntry(model.selectedEntry!!, resources, hostServices).show(
flowPaneHeader.scene.window,
contextMenuEvent.screenX,
contextMenuEvent.screenY
@ -279,24 +293,24 @@ class DetailsController(
private fun lazyUpdateTabContent(selectedTabId: String?) {
when (selectedTabId) {
"tabWords" -> {
if (!state.finishedFindingWordsContaining.value) {
state.findWordsContaining()
if (!model.finishedFindingWordsContaining) {
interactor.findWordsContaining()
}
if (!state.finishedFindingWordsBeginning.value) {
state.findWordsBeginning()
if (!model.finishedFindingWordsBeginning) {
interactor.findWordsBeginning()
}
}
"tabCharacters" -> {
if (state.finishedFindingCharacters.value) return
if (model.finishedFindingCharacters) return
state.findCharacters()
interactor.findCharacters()
}
"tabSentences" -> {
if (state.finishedFindingSentences.value) return
if (model.finishedFindingSentences) return
state.findSentences()
interactor.findSentences()
}
else -> {}

View File

@ -1,10 +1,10 @@
package com.marvinelsen.willow.ui.controllers
import com.marvinelsen.willow.State
import com.marvinelsen.willow.Model
import javafx.fxml.FXML
@Suppress("UnusedPrivateProperty", "UnusedPrivateMember")
class MainController(private val state: State) {
class MainController(private val model: Model) {
@FXML
private fun initialize() {
// no-op

View File

@ -1,6 +1,7 @@
package com.marvinelsen.willow.ui.controllers
import com.marvinelsen.willow.State
import com.marvinelsen.willow.Interactor
import com.marvinelsen.willow.Model
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.ui.dialogs.PreferencesDialog
import javafx.application.Platform
@ -11,7 +12,7 @@ import javafx.scene.control.MenuItem
import java.util.ResourceBundle
@Suppress("UnusedPrivateMember")
class MenuController(private val state: State, private val config: Config) {
class MenuController(private val model: Model, private val interactor: Interactor, private val config: Config) {
@FXML
private lateinit var resources: ResourceBundle
@ -26,8 +27,8 @@ class MenuController(private val state: State, private val config: Config) {
@FXML
private fun initialize() {
menuItemCopyPronunciation.disableProperty().bind(Bindings.isNull(state.selectedEntry))
menuItemCopyHeadword.disableProperty().bind(Bindings.isNull(state.selectedEntry))
menuItemCopyPronunciation.disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
menuItemCopyHeadword.disableProperty().bind(Bindings.isNull(model.selectedEntryProperty()))
}
@FXML
@ -47,11 +48,11 @@ class MenuController(private val state: State, private val config: Config) {
@FXML
private fun onMenuItemCopyPronunciationAction() {
state.copyPronunciationOfSelectedEntry()
interactor.copyPronunciationOfSelectedEntry()
}
@FXML
private fun onMenuItemCopyHeadwordAction() {
state.copyHeadwordOfSelectedEntry()
interactor.copyHeadwordOfSelectedEntry()
}
}

View File

@ -1,13 +1,14 @@
package com.marvinelsen.willow.ui.controllers
import com.marvinelsen.willow.State
import com.marvinelsen.willow.Interactor
import com.marvinelsen.willow.Model
import com.marvinelsen.willow.domain.SearchMode
import javafx.fxml.FXML
import javafx.scene.control.Button
import javafx.scene.control.TextField
import javafx.scene.control.ToggleGroup
class SearchController(private val state: State) {
class SearchController(private val model: Model, private val interactor: Interactor) {
@FXML
private lateinit var buttonUndo: Button
@ -26,8 +27,8 @@ class SearchController(private val state: State) {
textFieldSearch.textProperty().addListener { _, _, _ -> search() }
searchModeToggleGroup.selectedToggleProperty().addListener { _, _, _ -> search() }
buttonUndo.disableProperty().bind(state.canUndo.not())
buttonRedo.disableProperty().bind(state.canRedo.not())
buttonUndo.disableProperty().bind(model.canUndo.not())
buttonRedo.disableProperty().bind(model.canRedo.not())
}
private fun search() {
@ -38,14 +39,14 @@ class SearchController(private val state: State) {
return
}
state.search(searchQuery, searchMode)
interactor.search(searchQuery, searchMode)
}
fun onButtonRedoAction() {
state.redoSelection()
interactor.redoSelection()
}
fun onButtonUndoAction() {
state.undoSelection()
interactor.undoSelection()
}
}

View File

@ -1,8 +1,9 @@
package com.marvinelsen.willow.ui.controllers
import com.marvinelsen.willow.State
import com.marvinelsen.willow.Interactor
import com.marvinelsen.willow.Model
import com.marvinelsen.willow.config.Config
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.ui.cells.DictionaryEntryCellFactory
import javafx.application.HostServices
import javafx.beans.binding.Bindings
@ -13,7 +14,8 @@ import javafx.scene.control.ProgressIndicator
import java.util.ResourceBundle
class SearchResultsController(
private val state: State,
private val model: Model,
private val interactor: Interactor,
private val config: Config,
private val hostServices: HostServices,
) {
@ -35,21 +37,21 @@ class SearchResultsController(
@Suppress("UnusedPrivateMember")
private fun initialize() {
listViewSearchResults.cellFactory = DictionaryEntryCellFactory(resources, config, hostServices)
listViewSearchResults.items = state.searchResults
listViewSearchResults.items = model.searchResults
listViewSearchResults
.disableProperty()
.bind(Bindings.or(state.isSearching, Bindings.isEmpty(state.searchResults)))
.bind(Bindings.or(model.isSearchingProperty(), Bindings.isEmpty(model.searchResults)))
progressIndicatorEntries.visibleProperty().bind(state.isSearching)
progressIndicatorEntries.visibleProperty().bind(model.isSearchingProperty())
labelNoEntriesFound
.visibleProperty()
.bind(Bindings.and(Bindings.isEmpty(state.searchResults), Bindings.not(state.isSearching)))
.bind(Bindings.and(Bindings.isEmpty(model.searchResults), Bindings.not(model.isSearchingProperty())))
listViewSearchResults.selectionModel.selectedItemProperty().addListener { _, _, newValue: DictionaryEntry? ->
if (newValue == null) {
return@addListener
}
state.normalSelect(newValue)
interactor.normalSelect(newValue)
}
}
}

View File

@ -1,7 +1,7 @@
package com.marvinelsen.willow.ui.util
import com.marvinelsen.willow.domain.entities.DictionaryEntry
import com.marvinelsen.willow.domain.entities.Sentence
import com.marvinelsen.willow.domain.objects.DictionaryEntry
import com.marvinelsen.willow.domain.objects.Sentence
import javafx.application.HostServices
import javafx.event.EventHandler
import javafx.scene.control.ContextMenu