Skip to content

Commit

Permalink
Merge pull request #1145 from Bible-Translation-Tools/dh-dark-mode-wa…
Browse files Browse the repository at this point in the history
…veforms

Dark mode waveforms
  • Loading branch information
darrellcolehill authored Jun 3, 2024
2 parents 4ec9fc4 + 65f94ac commit 9a0e1ba
Show file tree
Hide file tree
Showing 18 changed files with 341 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,31 @@
*/
package org.wycliffeassociates.otter.common.data

const val WAV_COLOR_LIGHT = "#66768B"
const val WAV_BACKGROUND_COLOR_LIGHT = "#FFFFFF"
const val WAV_COLOR_DARK = "#808080"
const val WAV_BACKGROUND_COLOR_DARK = "#343434"

enum class ColorTheme(val titleKey: String, val styleClass: String = "") {
LIGHT("light", "light-theme"),
DARK("dark", "dark-theme"),
SYSTEM("system");
}

data class WaveformColors(val wavColorHex: String, val backgroundColorHex: String)

fun getWaveformColors(theme: ColorTheme): WaveformColors {
return when (theme) {
ColorTheme.LIGHT -> {
WaveformColors(WAV_COLOR_LIGHT, WAV_BACKGROUND_COLOR_LIGHT)
}

ColorTheme.DARK -> {
WaveformColors(WAV_COLOR_DARK, WAV_BACKGROUND_COLOR_DARK)
}

else -> {
WaveformColors(WAV_COLOR_LIGHT, WAV_BACKGROUND_COLOR_LIGHT)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,6 @@ class WaveformFrame(
styleClass.add("scrolling-waveform-frame__center")
alignment = Pos.CENTER

themeProperty.onChange {
it?.let { theme ->
adjustWaveformColorByTheme(theme, waveformColorEffect)
}
}

/**
* Putting this in the middle of the borderpane below will result in one of the following errors:
*
Expand Down Expand Up @@ -211,6 +205,7 @@ class WaveformFrame(
onRewindProperty.value?.invoke(speed)
it.consume()
}

KeyCode.RIGHT -> {
onFastForwardProperty.value?.invoke(speed)
it.consume()
Expand All @@ -225,6 +220,7 @@ class WaveformFrame(
onResumeMediaProperty.value?.invoke()
it.consume()
}

KeyCode.ENTER, KeyCode.SPACE -> {
onToggleMediaProperty.value?.invoke()
it.consume()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.wycliffeassociates.otter.jvm.controls.waveform.AudioSlider
import org.wycliffeassociates.otter.jvm.controls.waveform.MarkerPlacementWaveform
import org.wycliffeassociates.otter.jvm.markerapp.app.viewmodel.VerseMarkerViewModel
import org.wycliffeassociates.otter.jvm.utils.ListenerDisposer
import org.wycliffeassociates.otter.jvm.utils.onChangeWithDisposer
import org.wycliffeassociates.otter.jvm.workbookplugin.plugin.PluginCloseRequestEvent
import org.wycliffeassociates.otter.jvm.workbookplugin.plugin.PluginEntrypoint
import tornadofx.*
Expand All @@ -40,14 +41,17 @@ class MarkerView : PluginEntrypoint() {

private var slider: AudioSlider? = null
private var minimap: MinimapFragment? = null

private val disposables = mutableListOf<ListenerDisposer>()
private var colorThemeDisposer: ListenerDisposer? = null

override fun onDock() {
super.onDock()
viewModel.onDock {
viewModel.compositeDisposable.add(
viewModel.waveform.observeOnFx().subscribe { waveform.addWaveformImage(it) }
viewModel.waveform
.observeOnFx()
.subscribe {
waveform.addWaveformImage(it)
}
)
}
slider?.let {
Expand All @@ -56,8 +60,30 @@ class MarkerView : PluginEntrypoint() {
waveform.markers.bind(viewModel.markers) { it }
waveform.initializeMarkers()
viewModel.cleanupWaveform = waveform::cleanup

subscribeOnThemeChange()
}

override fun onUndock() {
super.onUndock()
colorThemeDisposer?.dispose()
}


private fun subscribeOnThemeChange() {
viewModel.themeColorProperty
.onChangeWithDisposer {
viewModel.onThemeChange()
slider?.let {
viewModel.initializeAudioController(it)
}
waveform.markers.bind(viewModel.markers) { it }
waveform.initializeMarkers()

}.apply { colorThemeDisposer = this }
}


init {
tryImportStylesheet(resources["/css/verse-marker-app.css"])
tryImportStylesheet(resources["/css/scrolling-waveform.css"])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import org.wycliffeassociates.otter.common.data.audio.AudioMarker
import org.wycliffeassociates.otter.common.data.audio.BookMarker
import org.wycliffeassociates.otter.common.data.audio.ChapterMarker
import org.wycliffeassociates.otter.common.data.audio.VerseMarker
import org.wycliffeassociates.otter.common.data.getWaveformColors
import org.wycliffeassociates.otter.jvm.controls.model.SECONDS_ON_SCREEN
import org.wycliffeassociates.otter.jvm.workbookplugin.plugin.PluginCloseFinishedEvent
import org.wycliffeassociates.otter.common.domain.model.MarkerItem
Expand All @@ -54,9 +55,6 @@ import org.wycliffeassociates.otter.jvm.controls.waveform.ObservableWaveformBuil
import org.wycliffeassociates.otter.jvm.controls.waveform.WAVEFORM_MAX_HEIGHT
import java.util.regex.Pattern

private const val WAV_COLOR = "#0A337390"
private const val BACKGROUND_COLOR = "#FFFFFF"

class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {

private val logger = LoggerFactory.getLogger(VerseMarkerViewModel::class.java)
Expand Down Expand Up @@ -90,6 +88,7 @@ class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {
val compositeDisposable = CompositeDisposable()
override val positionProperty = SimpleDoubleProperty(0.0)
override var imageWidthProperty = SimpleDoubleProperty()
private val onThemeChangeAction = SimpleObjectProperty<() -> Unit>()

override var resumeAfterScroll = false

Expand All @@ -102,6 +101,7 @@ class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {
}

fun onDock(op: () -> Unit) {
onThemeChangeAction.set(op)
timer?.start()
isLoadingProperty.set(true)
val audio = loadAudio()
Expand All @@ -124,6 +124,18 @@ class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {
)
}


fun onThemeChange() {
val audioFile = loadAudio()
audioFile.let {
pause()
asyncBuilder.cancel()
cleanupWaveform()
createWaveformImages(OratureAudioFile(it.file))
onThemeChangeAction.value.invoke()
}
}

private fun loadAudio(): OratureAudioFile {
val scope = scope as ParameterizedScope
val player = (scope.workspace.params["audioConnectionFactory"] as AudioConnectionFactory).getPlayer()
Expand Down Expand Up @@ -167,7 +179,7 @@ class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {
if (bookSlug == null || chapterNumber == null) return arrayOf()

val chapterNumber = Integer.parseInt(chapterNumber)
return when(chapterNumber) {
return when (chapterNumber) {
1 -> arrayOf(BookMarker(bookSlug, 0), ChapterMarker(chapterNumber, 0))
else -> arrayOf(ChapterMarker(chapterNumber, 0))
}
Expand Down Expand Up @@ -252,21 +264,23 @@ class VerseMarkerViewModel : ViewModel(), IMarkerViewModel {
private fun createWaveformImages(audio: OratureAudioFile) {
imageWidthProperty.set(computeImageWidth(SECONDS_ON_SCREEN))

val waveformColors = getWaveformColors(themeColorProperty.value)

waveform = asyncBuilder.buildAsync(
audio.reader(),
width = imageWidthProperty.value.toInt(),
height = Screen.getMainScreen().platformHeight,
wavColor = Color.web(WAV_COLOR),
background = Color.web(BACKGROUND_COLOR)
wavColor = Color.web(waveformColors.wavColorHex),
background = Color.web(waveformColors.backgroundColorHex)
)

asyncBuilder
.build(
audio.reader(),
width = Screen.getMainScreen().platformWidth,
height = 50,
wavColor = Color.web(WAV_COLOR),
background = Color.web(BACKGROUND_COLOR)
wavColor = Color.web(waveformColors.wavColorHex),
background = Color.web(waveformColors.backgroundColorHex)
)
.observeOnFx()
.map { image ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import org.junit.Test
import org.wycliffeassociates.otter.common.audio.AudioFileReader
import org.wycliffeassociates.otter.common.audio.pcm.PcmFile
import org.wycliffeassociates.otter.common.audio.pcm.PcmOutputStream
import org.wycliffeassociates.otter.common.data.ColorTheme
import org.wycliffeassociates.otter.common.data.workbook.Chapter
import org.wycliffeassociates.otter.common.data.workbook.Chunk
import org.wycliffeassociates.otter.common.data.workbook.Workbook
Expand All @@ -28,6 +29,7 @@ import org.wycliffeassociates.otter.common.domain.narration.testDataRootFilePath
import org.wycliffeassociates.otter.common.domain.narration.testDirWithAudio
import org.wycliffeassociates.otter.common.domain.narration.testDirWithoutAudio
import org.wycliffeassociates.otter.jvm.workbookapp.ui.narration.waveform.NarrationWaveformRenderer
import java.awt.Color
import java.awt.image.BufferedImage
import java.io.File
import java.io.Reader
Expand Down Expand Up @@ -127,7 +129,9 @@ class NarrationRenderingTest {
},
readerDrawable = readerDrawable
)
val renderer = NarrationWaveformRenderer(scene, rendererWidth, rendererHeight)

val colorThemeObservable = Observable.just(ColorTheme.LIGHT)
val renderer = NarrationWaveformRenderer(scene, rendererWidth, rendererHeight, colorThemeObservable)

val location = 0
val experiments = 10
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ class AppPreferences @Inject constructor(database: AppDatabase) : IAppPreference
}

override fun appTheme(): Single<String> {
return getString(APP_THEME_KEY, ColorTheme.LIGHT.name) // default theme color
return getString(APP_THEME_KEY, ColorTheme.SYSTEM.name) // default theme color
}

override fun setAppTheme(theme: String): Completable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,29 +88,28 @@ class SettingsView : View() {
vbox {
addClass("app-drawer__section")

// TODO: show theme color options when dark mode is ready
// label(messages["colorTheme"]).apply {
// addClass("app-drawer__subtitle--small")
// }
//
// combobox(viewModel.selectedThemeProperty, viewModel.supportedThemes) {
// addClass("wa-combobox")
// fitToParentWidth()
//
// cellFormat {
// val view = ComboboxItem()
// graphic = view.apply {
// topTextProperty.set(messages[it.titleKey])
// }
// }
//
// buttonCell = IconComboBoxCell(FontIcon(MaterialDesign.MDI_BRIGHTNESS_6)) {
// it?.let { FX.messages[it.titleKey] } ?: ""
// }
// overrideDefaultKeyEventHandler {
// fire(ThemeColorEvent(this@SettingsView::class, it))
// }
// }
label(messages["colorTheme"]).apply {
addClass("app-drawer__subtitle--small")
}

combobox(viewModel.selectedThemeProperty, viewModel.supportedThemes) {
addClass("wa-combobox")
fitToParentWidth()

cellFormat {
val view = ComboboxItem()
graphic = view.apply {
topTextProperty.set(messages[it.titleKey])
}
}

buttonCell = IconComboBoxCell(FontIcon(MaterialDesign.MDI_BRIGHTNESS_6)) {
it?.let { FX.messages[it.titleKey] } ?: ""
}
overrideDefaultKeyEventHandler {
fire(ThemeColorEvent(this@SettingsView::class, it))
}
}

label(messages["language"]).apply {
addClass("app-drawer__subtitle--small")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ class NarrationPage : View() {

false -> { // regular navigation
viewModel.onDock()
viewModel.colorThemeProperty.bind(settingsViewModel.appColorMode)
narrationHeader.onDock()
audioWorkspaceView.onDock()
teleprompterView.onDock()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import javafx.scene.canvas.GraphicsContext
import org.slf4j.LoggerFactory
import org.wycliffeassociates.otter.common.audio.AudioFileReader
import org.wycliffeassociates.otter.common.audio.DEFAULT_SAMPLE_RATE
import org.wycliffeassociates.otter.common.data.ColorTheme
import org.wycliffeassociates.otter.common.data.audio.AudioMarker
import org.wycliffeassociates.otter.common.data.audio.BookMarker
import org.wycliffeassociates.otter.common.data.audio.ChapterMarker
Expand Down Expand Up @@ -99,6 +100,8 @@ class NarrationViewModel : ViewModel() {

private lateinit var volumeBar: VolumeBar

val colorThemeProperty = SimpleObjectProperty<ColorTheme>()

val recordAgainVerseIndexProperty = SimpleObjectProperty<Int?>()
var recordAgainVerseIndex by recordAgainVerseIndexProperty

Expand Down Expand Up @@ -305,6 +308,7 @@ class NarrationViewModel : ViewModel() {
subscribeTaskRunnerBusyChanged()
rendererAudioReader = narration.audioReader
rendererAudioReader.open()

renderer = NarrationWaveformRenderer(
AudioScene(
rendererAudioReader,
Expand All @@ -320,7 +324,8 @@ class NarrationViewModel : ViewModel() {
DEFAULT_SAMPLE_RATE
),
Screen.getMainScreen().width,
Screen.getMainScreen().height
Screen.getMainScreen().height,
colorThemeProperty.toObservable()
)
totalAudioSizeProperty.set(rendererAudioReader.totalFrames)
}
Expand Down
Loading

0 comments on commit 9a0e1ba

Please sign in to comment.