Basic stuff working

This commit is contained in:
2025-02-02 15:32:19 +01:00
parent 450713ae38
commit 0d424ac413
6 changed files with 195 additions and 43 deletions

3
.gitignore vendored
View File

@@ -11,6 +11,9 @@ captures
.externalNativeBuild .externalNativeBuild
.cxx .cxx
*.xcodeproj/* *.xcodeproj/*
data/**
composeApp/data/**
composeApp/src/commonMain/resources/media/**
!*.xcodeproj/project.pbxproj !*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/ !*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/ !*.xcodeproj/project.xcworkspace/

View File

@@ -83,6 +83,9 @@ kotlin {
implementation(libs.koin.core) implementation(libs.koin.core)
implementation(libs.koin.compose) implementation(libs.koin.compose)
implementation(libs.koin.compose.viewmodel) implementation(libs.koin.compose.viewmodel)
implementation(libs.composeIcons.tablerIcons)
implementation(libs.composeIcons.fontAwesome)
implementation(libs.korau)
} }

View File

@@ -1,5 +1,6 @@
package org.neutrino.ktans.view package org.neutrino.ktans.view
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@@ -12,12 +13,14 @@ import androidx.compose.material.Text
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.material.TextField import androidx.compose.material.TextField
import androidx.compose.material.IconButton import androidx.compose.material.IconButton
import androidx.compose.material.Icon import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Clear import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import kotlinx.coroutines.flow.observeOn import kotlinx.coroutines.flow.observeOn
import org.koin.compose.koinInject import org.koin.compose.koinInject
@@ -28,6 +31,16 @@ import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import compose.icons.TablerIcons
import compose.icons.tablericons.Table
import androidx.compose.foundation.layout.Arrangement
import compose.icons.FontAwesomeIcons
import compose.icons.fontawesomeicons.Solid
import compose.icons.tablericons.ArrowBigRight
import compose.icons.fontawesomeicons.solid.PlayCircle
import models.Term
import models.TermFull
import kotlinx.coroutines.*
@Composable @Composable
fun RowScope.TableCell( fun RowScope.TableCell(
@@ -39,37 +52,76 @@ fun RowScope.TableCell(
Modifier Modifier
.border(1.dp, Color.Black) .border(1.dp, Color.Black)
.weight(weight) .weight(weight)
.padding(8.dp) .padding(4.dp)
) )
} }
fun groupByString1(terms: List<TermFull>): MutableList<MutableList<TermFull>> {
val fullList: MutableList<MutableList<TermFull>> = mutableListOf()
var lastTerm: TermFull? = null
var termsEq: MutableList<TermFull> = mutableListOf()
for (t in terms) {
if (lastTerm == null) {
termsEq += t
} else {
if (lastTerm.string1 == t.string1){
termsEq += t
} else {
fullList += termsEq
termsEq = mutableListOf()
termsEq += t
}
}
lastTerm = t
}
fullList += termsEq
return fullList
}
@Composable @Composable
fun SearchBarTextField(viewModel: MainModelView) { fun SearchBarTextField(viewModel: MainModelView) {
val query = remember { mutableStateOf("") } val query = remember { mutableStateOf("") }
val columnViewType = remember { mutableStateOf(false) }
Column { Column {
TextField( Row(
value = query.value, verticalAlignment = Alignment.CenterVertically,
onValueChange = { // horizontalArrangement = Arrangement.End,
query.value = it modifier = Modifier.background(Color.LightGray)
viewModel.getTerms(query.value) ) {
},
placeholder = { Text("Prelož...") }, TextField(
singleLine = true, value = query.value,
leadingIcon = { Icon(Icons.Filled.Search, contentDescription = "Search Icon") }, onValueChange = {
trailingIcon = { query.value = it
if (query.value.isNotEmpty()) { viewModel.getTerms(query.value)
IconButton(onClick = { },
query.value = "" placeholder = { Text("Prelož...") },
viewModel.clearSearch() singleLine = true,
}) { leadingIcon = { Icon(Icons.Filled.Search, contentDescription = "Search Icon") },
Icon(Icons.Filled.Clear, contentDescription = "Clear Text") trailingIcon = {
} if (query.value.isNotEmpty()) {
} IconButton(onClick = {
}, query.value = ""
modifier = Modifier viewModel.clearSearch()
.fillMaxWidth() }) {
) Icon(Icons.Filled.Clear, contentDescription = "Clear Text")
}
}
},
modifier = Modifier.weight(3f)
)
Row (Modifier.width(155.dp).border(width = 2.dp, Color.Black)) {
Spacer(modifier = Modifier.padding(2.dp))
Icon(TablerIcons.Table, contentDescription = "Table View", modifier = Modifier.size(width = 50.dp, height = 50.dp))
Spacer(modifier = Modifier.padding(2.dp))
Icon(TablerIcons.ArrowBigRight, contentDescription = "Table View", modifier = Modifier.size(width = 50.dp, height = 50.dp))
Spacer(modifier = Modifier.padding(2.dp))
Icon(Icons.Filled.Settings, contentDescription = "Table View", modifier = Modifier.size(width = 50.dp, height = 50.dp))
//Spacer(modifier = Modifier.fillMaxWidth())
}
}
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) { Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally ) {
val terms by viewModel.terms.collectAsState() val terms by viewModel.terms.collectAsState()
@@ -77,27 +129,85 @@ fun SearchBarTextField(viewModel: MainModelView) {
if (terms != null) { if (terms != null) {
SelectionContainer { SelectionContainer {
Column { Column {
Row(Modifier.background(Color.Gray)) { if (columnViewType.value) {
TableCell(text = "Anglicky", weight = .5f) Row(Modifier.background(Color.Gray)) {
TableCell(text = "Slovensky", weight = .5f) TableCell(text = "Anglicky", weight = .5f)
} TableCell(text = "Slovensky", weight = .5f)
val column1Weight = .5f // 50% }
val column2Weight = .5f // 50% val column1Weight = .5f // 50%
// The LazyColumn will be our table. Notice the use of the weights below val column2Weight = .5f // 50%
LazyColumn(Modifier.fillMaxSize().padding(0.dp)) { // The LazyColumn will be our table. Notice the use of the weights below
// Here is the header LazyColumn(Modifier.fillMaxSize().padding(0.dp)) {
// Here is the header
items(items = terms!!, itemContent = { t -> items(items = terms!!, itemContent = { t ->
Row(Modifier.fillMaxWidth()) { Row(Modifier.fillMaxWidth()) {
TableCell(text = t.string1, weight = column1Weight) TableCell(text = t.string1, weight = column1Weight)
TableCell(text = t.string2, weight = column2Weight) TableCell(text = t.string2, weight = column2Weight)
} }
}) })
}
} else {
val terms2: MutableList<MutableList<TermFull>> = groupByString1(terms!!)
LazyColumn(Modifier.fillMaxSize().padding(0.dp)) {
var i=0
var rowBackground = Color.LightGray
items(items = terms2, itemContent = { t2 ->
var t : TermFull? = null
if (t2.size > 0) t = t2[0]
else return@items
when ( i++ % 2 ) {
0 -> rowBackground = Color.LightGray
1 -> rowBackground = Color.Gray
}
Row(Modifier.fillMaxWidth().background(color = rowBackground)) {
Column {
Row( verticalAlignment = Alignment.CenterVertically) {
Text(t.string1, fontWeight = FontWeight.Bold)
for (p in t.pronunciations!!) {
Spacer(modifier = Modifier.padding(2.dp))
if (p.ipa != null) {
var color = Color.Blue
when (p.typeId) {
1 -> color = Color.Green
2 -> color = Color.Red
3 -> color = Color.Blue
}
Text("[${p.ipa}]", color = color)
}
if (p.filename != null) {
IconButton(
modifier = Modifier.size(20.dp),
onClick = {
viewModel.playSound("media/${p.filename}")
}) {
Icon(FontAwesomeIcons.Solid.PlayCircle,contentDescription = "Play sound",Modifier.size(20.dp).padding(start = 2.dp),)
}
}
Spacer(modifier = Modifier.padding(2.dp))
}
}
val str2 = t2.joinToString(separator = ", ") { it.string2 }
Text(text = str2, modifier = Modifier.padding(start = 20.dp))
Spacer(modifier = Modifier
.border(1.dp, Color.Black)
.padding(1.dp).fillMaxWidth())
}
}
})
}
} }
} }
} }
} }

View File

@@ -2,16 +2,18 @@ package org.neutrino.ktans.viewmodel
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import korlibs.audio.sound.*
import korlibs.io.file.std.resourcesVfs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import models.TermFull import models.TermFull
import service.TermService
import service.TermServiceImpl
import service.DatabaseFactory.getTranslationForLanguages import service.DatabaseFactory.getTranslationForLanguages
import service.SearchType import service.SearchType
import kotlinx.coroutines.Dispatchers import service.TermServiceImpl
import korlibs.audio.format.*
class MainModelView(private val repository: TermServiceImpl): ViewModel() { class MainModelView(private val repository: TermServiceImpl): ViewModel() {
val terms : StateFlow<List<TermFull>?> get() = _terms val terms : StateFlow<List<TermFull>?> get() = _terms
private val _terms = MutableStateFlow<List<TermFull>?>(null) private val _terms = MutableStateFlow<List<TermFull>?>(null)
@@ -28,5 +30,16 @@ class MainModelView(private val repository: TermServiceImpl): ViewModel() {
} }
fun clearSearch() { fun clearSearch() {
_terms.value = listOf() _terms.value = listOf()
} }
fun playSound(file: String) {
viewModelScope.launch {
val sound = resourcesVfs[file.replace("ogg","mp3")].readMusic()
sound.play()
}
}
} }

View File

@@ -1,6 +1,10 @@
sound {
database = "./data/media"
}
h2 { h2 {
driver = org.h2.Driver driver = org.h2.Driver
url = "jdbc:h2:file:./data/%s;DB_CLOSE_DELAY=-1;" url = "jdbc:h2:file:./data/%s;DB_CLOSE_DELAY=-1;"
user = "sa" user = "sa"
password = "" password = ""
} }

View File

@@ -30,6 +30,7 @@ junitVersion = "5.11.3"
kformat = "0.11" kformat = "0.11"
koinAndroidxCompose = "4.0.2)" koinAndroidxCompose = "4.0.2)"
koinCore = "3.1.2" koinCore = "3.1.2"
korauOggVorbisJvm = "1.8.6"
kotlin = "2.1.0" kotlin = "2.1.0"
ksp = "2.1.0-1.0.29" ksp = "2.1.0-1.0.29"
kotlinSerializationCompilerPluginEmbeddable = "1.9.22" kotlinSerializationCompilerPluginEmbeddable = "1.9.22"
@@ -72,8 +73,24 @@ runtimeLivedata = "1.7.6"
runtimeLivedataVersion = "1.0.0-beta01" runtimeLivedataVersion = "1.0.0-beta01"
symbolProcessingApi = "2.1.0-1.0.29" symbolProcessingApi = "2.1.0-1.0.29"
lifecycleLivedataCoreKtx = "2.8.7" lifecycleLivedataCoreKtx = "2.8.7"
composeIcons = "1.1.1"
korau = "4.0.10"
[libraries] [libraries]
composeIcons-cssGg = { module = "br.com.devsrsouza.compose.icons:css-gg", version.ref = "composeIcons" }
composeIcons-weatherIcons = { module = "br.com.devsrsouza.compose.icons:erikflowers-weather-icons", version.ref = "composeIcons" }
composeIcons-evaIcons = { module = "br.com.devsrsouza.compose.icons:eva-icons", version.ref = "composeIcons" }
composeIcons-feather = { module = "br.com.devsrsouza.compose.icons:feather", version.ref = "composeIcons" }
composeIcons-fontAwesome = { module = "br.com.devsrsouza.compose.icons:font-awesome", version.ref = "composeIcons" }
composeIcons-lineAwesome = { module = "br.com.devsrsouza.compose.icons:line-awesome", version.ref = "composeIcons" }
composeIcons-linea = { module = "br.com.devsrsouza.compose.icons:linea", version.ref = "composeIcons" }
composeIcons-octicons = { module = "br.com.devsrsouza.compose.icons:octicons", version.ref = "composeIcons" }
composeIcons-simpleIcons = { module = "br.com.devsrsouza.compose.icons:simple-icons", version.ref = "composeIcons" }
composeIcons-tablerIcons = { module = "br.com.devsrsouza.compose.icons:tabler-icons", version.ref = "composeIcons" }
korau = { module = "com.soywiz.korlibs.korau:korau", version.ref = "korau" }
androidx-core-ktx-v190 = { module = "androidx.core:core-ktx", version.ref = "coreKtx" } androidx-core-ktx-v190 = { module = "androidx.core:core-ktx", version.ref = "coreKtx" }
androidx-lifecycle-livedata-core = { module = "androidx.lifecycle:lifecycle-livedata-core", version.ref = "lifecycleLivedataCore" } androidx-lifecycle-livedata-core = { module = "androidx.lifecycle:lifecycle-livedata-core", version.ref = "lifecycleLivedataCore" }
androidx-lifecycle-livedata-ktx-v261 = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidxLifecycleLivedataKtx" } androidx-lifecycle-livedata-ktx-v261 = { module = "androidx.lifecycle:lifecycle-livedata-ktx", version.ref = "androidxLifecycleLivedataKtx" }
@@ -106,6 +123,8 @@ kformat = { module = "de.m3y.kformat:kformat", version.ref = "kformat" }
koin-compose = { module = "io.insert-koin:koin-compose" } koin-compose = { module = "io.insert-koin:koin-compose" }
koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" } koin-compose-viewmodel = { module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koinComposeMultiplatform" }
korau-macosarm64 = { module = "com.soywiz.korlibs.korau:korau-macosarm64", version.ref = "korau" }
korau-ogg-vorbis-jvm = { module = "com.soywiz.korlibs.korau:korau-ogg-vorbis-jvm", version.ref = "korauOggVorbisJvm" }
kotlin-serialization-compiler-plugin-embeddable = { module = "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable", version.ref = "kotlinSerializationCompilerPluginEmbeddable" } kotlin-serialization-compiler-plugin-embeddable = { module = "org.jetbrains.kotlin:kotlin-serialization-compiler-plugin-embeddable", version.ref = "kotlinSerializationCompilerPluginEmbeddable" }
kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" } kotlin-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }