Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge Feature/2 create knowledge category #15

Merged
merged 28 commits into from
Sep 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
460c728
remove google run project file
TSampley Sep 28, 2024
f8e55b3
replace placeholder text in API
TSampley Sep 28, 2024
d1b4bb0
remove artifact registry
TSampley Sep 28, 2024
b33da10
Upgrade koin
TSampley Sep 28, 2024
fd2b43f
Add mockk to jvmSharedTest source set
TSampley Sep 28, 2024
3632bcc
Add setupKoin function for platforms
TSampley Sep 28, 2024
f9c3af8
replace explicit startKoin with setupKoin function
TSampley Sep 28, 2024
388f758
checkmodule of koin application
TSampley Sep 28, 2024
d6ee564
Add editor state enum
TSampley Sep 28, 2024
bf70b2e
Add category editor test case
TSampley Sep 28, 2024
524e91c
Add category editor view model to explorer view model
TSampley Sep 28, 2024
c78b7a9
replace explicit construction with inline constructor reference
TSampley Sep 28, 2024
5fcbe54
replace concept editor view model explicit constructor with inline bi…
TSampley Sep 28, 2024
db128f9
replace category editor view model explicit constructor with inline b…
TSampley Sep 28, 2024
452fd9e
remove category creator view model binding
TSampley Sep 28, 2024
2071e84
Swap concept creator view model for editor view model
TSampley Sep 28, 2024
ee7e7c7
implement category editor view model based on creator view model
TSampley Sep 28, 2024
4c29d69
rename CategoryCreator.kt -> -Editor
TSampley Sep 28, 2024
b134830
Add CategoryEditor to explorer Screen
TSampley Sep 28, 2024
bc480a7
Remove implementation by delegation
TSampley Sep 28, 2024
1838a16
Add expected content description
TSampley Sep 28, 2024
f664c5d
Fix wrong state set
TSampley Sep 28, 2024
828d51e
fix confirmation button with wrong text
TSampley Sep 28, 2024
ce24da4
observe finish events
TSampley Sep 28, 2024
0a73528
wrap category editor in dialog
TSampley Sep 28, 2024
7b51f38
move dialogs below constant UI
TSampley Sep 28, 2024
ff72e45
Create negative test cases
TSampley Sep 28, 2024
5970190
restrict checks to jvmTests
TSampley Sep 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/feature-pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ jobs:
uses: gradle/actions/setup-gradle@v3

- name: "Build: Assemble and Test entire project"
run: ./gradlew build
run: ./gradlew jvmTest

# - run: ./gradlew generate coverage report, upload test/coverage reports
2 changes: 1 addition & 1 deletion .github/workflows/main-pr-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@ jobs:
uses: gradle/actions/setup-gradle@v3

- name: "Build: Assemble and Test entire project"
run: ./gradlew build
run: ./gradlew jvmTest

# - run: ./gradlew generate coverage report, upload test/coverage reports
29 changes: 11 additions & 18 deletions api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ plugins {
alias(libs.plugins.kotlinJvm)
alias(libs.plugins.ktor)
`maven-publish`
alias(libs.plugins.artifactRegistry)
}

tasks.named<Zip>("distZip") {
Expand Down Expand Up @@ -33,27 +32,21 @@ kotlin {
}

application {
mainClass = "org.pointyware.replace-me.api.ServerKt"
mainClass = "org.pointyware.commonsense.api.ServerKt"
}

ktor {
fatJar {
archiveFileName = "replace-me-API-${version}.jar"
archiveFileName = "Common-Sense-API-${version}.jar"
}
}

//publishing {
// publications {
// create<MavenPublication>("maven") {
// groupId = "org.pointyware.replace-me"
// artifactId = "replace-me-api"
// from(components["java"])
// }
// }
// repositories {
// maven {
// val releaseURL = "artifactregistry://us-central1-maven.pkg.dev/<project-id>/<repo>"
// url = uri(releaseURL)
// }
// }
//}
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "org.pointyware.replace-me"
artifactId = "replace-me-api"
from(components["java"])
}
}
}
3 changes: 0 additions & 3 deletions api/project.toml

This file was deleted.

15 changes: 7 additions & 8 deletions app-android/src/main/java/CSApplication.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.pointyware.commonsense.android

import android.app.Application
import org.koin.core.context.startKoin
import org.koin.dsl.module
import org.pointyware.commonsense.android.di.androidModule
import org.pointyware.commonsense.shared.di.appModule
import org.pointyware.commonsense.shared.di.setupKoin

/**
* This is the production Common Sense application; it performs production environment setup.
Expand All @@ -12,11 +12,10 @@ class CSApplication: Application() {
override fun onCreate() {
super.onCreate()

startKoin {
modules(
androidModule(),
appModule()
)
}
setupKoin(
platformModule = module {
includes(androidModule(this@CSApplication))
}
)
}
}
7 changes: 6 additions & 1 deletion app-android/src/main/java/di/Module.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.pointyware.commonsense.android.di

import android.app.Application
import android.content.Context
import org.koin.dsl.module
import org.pointyware.commonsense.shared.entities.SharedFileResources
import org.pointyware.commonsense.shared.entities.SharedStringResources
Expand All @@ -9,9 +11,12 @@ import org.pointyware.commonsense.shared.ui.SharedFontResources
/**
*
*/
fun androidModule() = module {
fun androidModule(application: Application) = module {
single<SharedStringResources> { AndroidStringResources() }
single<SharedFontResources> { AndroidFontResources() }
single<SharedDrawableResources> { AndroidDrawableResources() }
single<SharedFileResources> { AndroidFileResources() }

single<Application> { application }
single<Context> { application }
}
8 changes: 2 additions & 6 deletions app-desktop/src/main/kotlin/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,11 @@ import org.pointyware.commonsense.shared.CommonSenseApp
import org.pointyware.commonsense.shared.FileViewModel
import org.pointyware.commonsense.shared.di.appModule
import org.pointyware.commonsense.shared.di.getDependencies
import org.pointyware.commonsense.shared.di.setupKoin

fun main() = application {

startKoin {
modules(
desktopModule(),
appModule()
)
}
setupKoin(platformModule = desktopModule())

val appDependencies = remember { getDependencies() }
val drawableResources = remember { appDependencies.getDrawableResources() }
Expand Down
2 changes: 2 additions & 0 deletions app-shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ kotlin {
dependsOn(commonTest)
dependencies {
implementation(libs.koin.test)

implementation(libs.mockk)
}
}

Expand Down
8 changes: 8 additions & 0 deletions app-shared/src/commonMain/kotlin/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.pointyware.commonsense.shared.di

import org.koin.core.context.startKoin
import org.koin.core.module.Module
import org.koin.dsl.module
import org.pointyware.commonsense.core.data.di.dataModule
Expand All @@ -15,6 +16,13 @@ import org.pointyware.commonsense.shared.FileViewModel
import org.pointyware.commonsense.shared.home.di.homeModule


fun setupKoin(platformModule: Module = module{}) = startKoin {
modules(
appModule(),
platformModule
)
}

fun appModule(): Module = module {
includes(
coreModule(),
Expand Down
26 changes: 12 additions & 14 deletions app-shared/src/jvmSharedTest/kotlin/di/KoinValidationTest.kt
Original file line number Diff line number Diff line change
@@ -1,34 +1,32 @@
package di

import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.HttpClientEngine
import org.koin.core.annotation.KoinExperimentalAPI
import org.koin.core.module.Module
import org.koin.test.check.checkKoinModules
import org.koin.test.verify.verify
import org.pointyware.commonsense.shared.di.appModule
import org.koin.core.KoinApplication
import org.koin.test.check.checkModules
import org.pointyware.commonsense.feature.ontology.di.ontologyJvmSharedModule
import org.pointyware.commonsense.shared.di.setupKoin
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import kotlin.test.Test

/**
*
*/
class KoinValidationTest {

lateinit var topLevelModule: Module
lateinit var koinApp: KoinApplication

@BeforeTest
fun setUp() {
topLevelModule = appModule()
koinApp = setupKoin(platformModule = ontologyJvmSharedModule())
}

@OptIn(KoinExperimentalAPI::class)
@Test
fun verifyKoinConfiguration() {
topLevelModule.verify(extraTypes = listOf(HttpClientEngine::class, HttpClientConfig::class))
@AfterTest
fun stopKoin() {
koinApp.close()
}

@Test
fun checkKoinModules() {
checkKoinModules(listOf(topLevelModule))
koinApp.checkModules()
}
}
1 change: 0 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ plugins {

alias(libs.plugins.commonsense.koin).apply(false)
alias(libs.plugins.commonsense.kmp).apply(false)
alias(libs.plugins.artifactRegistry).apply(false)
}

tasks.dokkaHtmlMultiModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.window.Dialog
import org.pointyware.commonsense.feature.ontology.category.viewmodels.CategoryExplorerEditorState
import org.pointyware.commonsense.feature.ontology.category.viewmodels.CategoryExplorerViewModel
import org.pointyware.commonsense.feature.ontology.ui.CategoryEditor
import org.pointyware.commonsense.feature.ontology.ui.ConceptEditor

/**
Expand All @@ -34,22 +36,6 @@ fun CategoryExplorerScreen(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
state.conceptEditor?.let { conceptEditorUiState ->
Dialog(
onDismissRequest = {
viewModel.onCancel()
}
) {
ConceptEditor(
state = conceptEditorUiState,
onNameChange = viewModel::onNameChange,
onDescriptionChange = viewModel::onDescriptionChange,
onConfirm = viewModel::onCommitConcept,
onCancel = viewModel::onCancel
)
}
}

CategoryExplorer(
state = mappedState,
modifier = Modifier.fillMaxSize(),
Expand All @@ -75,5 +61,38 @@ fun CategoryExplorerScreen(
)
}
}

when (val capture = state.editorState) {
is CategoryExplorerEditorState.Concept -> {
Dialog(
onDismissRequest = {
viewModel.onCancel()
}
) {
ConceptEditor(
state = capture.concept,
onNameChange = viewModel::onConceptNameChange,
onDescriptionChange = viewModel::onDescriptionChange,
onConfirm = viewModel::onCommitConcept,
onCancel = viewModel::onCancel
)
}
}
is CategoryExplorerEditorState.Category -> {
Dialog(
onDismissRequest = {
viewModel.onCancel()
}
) {
CategoryEditor(
state = capture.category,
onNameChange = viewModel::onCategoryNameChange,
onConfirm = viewModel::onCommitCategory,
onCancel = viewModel::onCancel
)
}
}
else -> { /* Show Nothing */ }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package org.pointyware.commonsense.feature.ontology.category.viewmodels

import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import org.pointyware.commonsense.core.viewmodels.ViewModel
import org.pointyware.commonsense.feature.ontology.category.interactors.CreateNewCategoryUseCase
import org.pointyware.commonsense.feature.ontology.entities.Category
import org.pointyware.commonsense.feature.ontology.viewmodels.CategoryEditorUiState

/**
* Maintains the state of a Category Editor UI, reflected in [state].
*/
interface CategoryEditorViewModel {
val state: StateFlow<CategoryEditorUiState>
val onFinish: SharedFlow<Unit>
fun prepareFor(category: Category?)
fun onNameChange(newName: String)
fun onConfirm()
fun onCancel()
}

/**
*/
class CategoryEditorViewModelImpl(
private val createNewCategoryUseCase: CreateNewCategoryUseCase,
): CategoryEditorViewModel, ViewModel() {

private val mutableState = MutableStateFlow(CategoryEditorUiState.Empty)
override val state: StateFlow<CategoryEditorUiState>
get() = mutableState.asStateFlow()

private val mutableFinish = MutableSharedFlow<Unit>()
override val onFinish: SharedFlow<Unit>
get() = mutableFinish.asSharedFlow()

override fun prepareFor(category: Category?) {
mutableState.update {
it.copy(name = category?.name ?: "")
}
}

override fun onNameChange(newName: String) {
mutableState.update {
it.copy(name = newName)
}
}

override fun onConfirm() {
viewModelScope.launch {
val state = state.value
createNewCategoryUseCase.invoke(state.name)
mutableFinish.emit(Unit)
}
}

override fun onCancel() {
viewModelScope.launch {
mutableFinish.emit(Unit)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.pointyware.commonsense.feature.ontology.category.viewmodels

import org.pointyware.commonsense.feature.ontology.Concept
import org.pointyware.commonsense.feature.ontology.entities.Category
import org.pointyware.commonsense.feature.ontology.viewmodels.CategoryEditorUiState
import org.pointyware.commonsense.feature.ontology.viewmodels.ConceptEditorUiState

/**
Expand All @@ -14,7 +15,7 @@ import org.pointyware.commonsense.feature.ontology.viewmodels.ConceptEditorUiSta
data class CategoryExplorerUiState(
val loading: Boolean = false,
val currentCategory: CategoryUiState,
val conceptEditor: ConceptEditorUiState? = null
val editorState: CategoryExplorerEditorState = CategoryExplorerEditorState.Disabled,
) {
companion object {
val Loading = CategoryExplorerUiState(true, CategoryUiState())
Expand All @@ -26,3 +27,13 @@ data class CategoryUiState(
val subcategories: List<Category> = emptyList(),
val concepts: List<Concept> = emptyList(),
)

sealed interface CategoryExplorerEditorState {
data object Disabled : CategoryExplorerEditorState
data class Concept(
val concept: ConceptEditorUiState
) : CategoryExplorerEditorState
data class Category(
val category: CategoryEditorUiState
) : CategoryExplorerEditorState
}
Loading