Basic stuff working
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -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/
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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 = ""
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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" }
|
||||||
|
|||||||
Reference in New Issue
Block a user