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
.cxx
*.xcodeproj/*
data/**
composeApp/data/**
composeApp/src/commonMain/resources/media/**
!*.xcodeproj/project.pbxproj
!*.xcodeproj/xcshareddata/
!*.xcodeproj/project.xcworkspace/

View File

@@ -83,6 +83,9 @@ kotlin {
implementation(libs.koin.core)
implementation(libs.koin.compose)
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
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background
import androidx.compose.ui.graphics.Color
@@ -12,12 +13,14 @@ import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.material.TextField
import androidx.compose.material.IconButton
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Search
import androidx.compose.material.icons.filled.Clear
import androidx.compose.material.icons.filled.Settings
import androidx.compose.runtime.Composable
import kotlinx.coroutines.flow.observeOn
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.items
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
fun RowScope.TableCell(
@@ -39,37 +52,76 @@ fun RowScope.TableCell(
Modifier
.border(1.dp, Color.Black)
.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
fun SearchBarTextField(viewModel: MainModelView) {
val query = remember { mutableStateOf("") }
val columnViewType = remember { mutableStateOf(false) }
Column {
TextField(
value = query.value,
onValueChange = {
query.value = it
viewModel.getTerms(query.value)
},
placeholder = { Text("Prelož...") },
singleLine = true,
leadingIcon = { Icon(Icons.Filled.Search, contentDescription = "Search Icon") },
trailingIcon = {
if (query.value.isNotEmpty()) {
IconButton(onClick = {
query.value = ""
viewModel.clearSearch()
}) {
Icon(Icons.Filled.Clear, contentDescription = "Clear Text")
}
}
},
modifier = Modifier
.fillMaxWidth()
)
Row(
verticalAlignment = Alignment.CenterVertically,
// horizontalArrangement = Arrangement.End,
modifier = Modifier.background(Color.LightGray)
) {
TextField(
value = query.value,
onValueChange = {
query.value = it
viewModel.getTerms(query.value)
},
placeholder = { Text("Prelož...") },
singleLine = true,
leadingIcon = { Icon(Icons.Filled.Search, contentDescription = "Search Icon") },
trailingIcon = {
if (query.value.isNotEmpty()) {
IconButton(onClick = {
query.value = ""
viewModel.clearSearch()
}) {
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 ) {
val terms by viewModel.terms.collectAsState()
@@ -77,27 +129,85 @@ fun SearchBarTextField(viewModel: MainModelView) {
if (terms != null) {
SelectionContainer {
Column {
Row(Modifier.background(Color.Gray)) {
TableCell(text = "Anglicky", weight = .5f)
TableCell(text = "Slovensky", weight = .5f)
}
val column1Weight = .5f // 50%
val column2Weight = .5f // 50%
// The LazyColumn will be our table. Notice the use of the weights below
LazyColumn(Modifier.fillMaxSize().padding(0.dp)) {
// Here is the header
if (columnViewType.value) {
Row(Modifier.background(Color.Gray)) {
TableCell(text = "Anglicky", weight = .5f)
TableCell(text = "Slovensky", weight = .5f)
}
val column1Weight = .5f // 50%
val column2Weight = .5f // 50%
// The LazyColumn will be our table. Notice the use of the weights below
LazyColumn(Modifier.fillMaxSize().padding(0.dp)) {
// Here is the header
items(items = terms!!, itemContent = { t ->
items(items = terms!!, itemContent = { t ->
Row(Modifier.fillMaxWidth()) {
TableCell(text = t.string1, weight = column1Weight)
TableCell(text = t.string2, weight = column2Weight)
}
Row(Modifier.fillMaxWidth()) {
TableCell(text = t.string1, weight = column1Weight)
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.viewModelScope
import korlibs.audio.sound.*
import korlibs.io.file.std.resourcesVfs
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import models.TermFull
import service.TermService
import service.TermServiceImpl
import service.DatabaseFactory.getTranslationForLanguages
import service.SearchType
import kotlinx.coroutines.Dispatchers
import service.TermServiceImpl
import korlibs.audio.format.*
class MainModelView(private val repository: TermServiceImpl): ViewModel() {
val terms : StateFlow<List<TermFull>?> get() = _terms
private val _terms = MutableStateFlow<List<TermFull>?>(null)
@@ -28,5 +30,16 @@ class MainModelView(private val repository: TermServiceImpl): ViewModel() {
}
fun clearSearch() {
_terms.value = listOf()
}
fun playSound(file: String) {
viewModelScope.launch {
val sound = resourcesVfs[file.replace("ogg","mp3")].readMusic()
sound.play()
}
}
}

View File

@@ -1,3 +1,7 @@
sound {
database = "./data/media"
}
h2 {
driver = org.h2.Driver
url = "jdbc:h2:file:./data/%s;DB_CLOSE_DELAY=-1;"

View File

@@ -30,6 +30,7 @@ junitVersion = "5.11.3"
kformat = "0.11"
koinAndroidxCompose = "4.0.2)"
koinCore = "3.1.2"
korauOggVorbisJvm = "1.8.6"
kotlin = "2.1.0"
ksp = "2.1.0-1.0.29"
kotlinSerializationCompilerPluginEmbeddable = "1.9.22"
@@ -72,8 +73,24 @@ runtimeLivedata = "1.7.6"
runtimeLivedataVersion = "1.0.0-beta01"
symbolProcessingApi = "2.1.0-1.0.29"
lifecycleLivedataCoreKtx = "2.8.7"
composeIcons = "1.1.1"
korau = "4.0.10"
[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-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" }
@@ -106,6 +123,8 @@ kformat = { module = "de.m3y.kformat:kformat", version.ref = "kformat" }
koin-compose = { module = "io.insert-koin:koin-compose" }
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-stdlib = { module = "org.jetbrains.kotlin:kotlin-stdlib", version.ref = "kotlin" }
kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }