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

Dev exp #93

Merged
merged 8 commits into from
Dec 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions .github/workflows/ci_clients.yml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,6 @@ jobs:
- name: Gradle cache
uses: gradle/actions/setup-gradle@v4

- name: Run unit tests
run: ./gradlew jvmTest
- name: Run unit tests on JS
run: ./gradlew jsTest

190 changes: 103 additions & 87 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,118 +1,134 @@
import com.google.devtools.ksp.gradle.KspTask

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.ksp)
idea
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.composeMultiplatform)
alias(libs.plugins.composeCompiler)
alias(libs.plugins.ksp)
idea
}

kotlin {
js(IR) {
browser()
binaries.executable()
}
js(IR) {
browser()
binaries.executable()
}

androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
androidTarget {
compilations.all {
kotlinOptions {
jvmTarget = "11"
}
}
}

jvm("desktop")
jvm("desktop")

listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp"
isStatic = true
}
listOf(
iosX64(),
iosArm64(),
iosSimulatorArm64()
).forEach { iosTarget ->
iosTarget.binaries.framework {
baseName = "ComposeApp"
isStatic = true
}
}

sourceSets {
commonMain {
kotlin.srcDirs("build/generated/ksp/commonMain/kotlin")
}
sourceSets {
commonMain {
kotlin.srcDirs("build/generated/ksp/commonMain/kotlin")
}
commonTest {
kotlin.srcDir("build/generated/ksp/test/kotlin")
}
dependencies {
ksp(libs.arrow.optics.ksp)
}

val desktopMain by getting
val desktopMain by getting

androidMain.dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
}
commonMain.dependencies {
implementation(projects.shared)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(libs.kotlin.immutableCollections)
implementation(libs.thirdparty.lottieMultiplatform)
implementation(libs.thirdparty.kamel)
implementation(libs.bundles.arrow)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
androidMain.dependencies {
implementation(compose.preview)
implementation(libs.androidx.activity.compose)
}
}

dependencies {
ksp(libs.arrow.optics.ksp)
commonMain.dependencies {
implementation(projects.shared)
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.ui)
implementation(compose.components.resources)
implementation(compose.components.uiToolingPreview)
implementation(libs.kotlin.immutableCollections)
implementation(libs.thirdparty.lottieMultiplatform)
implementation(libs.thirdparty.kamel)
implementation(libs.bundles.arrow)
}
commonTest.dependencies {
implementation(libs.bundles.test.kmp)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}
}
}

android {
namespace = "ivy.learn"
compileSdk = libs.versions.android.compileSdk.get().toInt()
namespace = "ivy.learn"
compileSdk = libs.versions.android.compileSdk.get().toInt()

sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")

defaultConfig {
applicationId = "ivy.learn"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
defaultConfig {
applicationId = "ivy.learn"
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
}
packaging {
resources {
excludes += "/META-INF/{AL2.0,LGPL2.1}"
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
buildTypes {
getByName("release") {
isMinifyEnabled = false
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
}

compose.experimental {
web.application {}
web.application {}
}

// Configure KSP to output to the commonMain directory
tasks.withType<KspTask> {
doLast {
copy {
from("build/generated/ksp/js/jsMain/kotlin")
into("build/generated/ksp/commonMain/kotlin")
include("**/*.kt")
}
delete("build/generated/ksp/js/jsMain/kotlin")
doLast {
fixKspConflicts()
}
}

fun fixKspConflicts() {
fun fixTarget(target: String) {
copy {
from("build/generated/ksp/$target/${target}Main/kotlin")
into("build/generated/ksp/commonMain/kotlin")
include("**/*.kt")
}
delete("build/generated/ksp/$target/${target}Main/kotlin")
}
fixTarget("js")
fixTarget("desktop")
fixTarget("android")
fixTarget("ios")
fixTarget("native")
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ class Analytics(
eventName: String,
params: Map<String, String>?,
) {
if (!enabled) return

appScope.launch {
if (sessionManager.getSession() is Session.LoggedIn) {
if (enabled && sessionManager.getSession() is Session.LoggedIn) {
trackLoggedAnalyticsEvent(
eventName = eventName,
params = params,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import androidx.compose.runtime.LaunchedEffect
import domain.GoogleAuthenticationUseCase
import domain.SessionManager
import domain.analytics.Analytics
import domain.analytics.Metrics
import domain.analytics.Source
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
Expand All @@ -15,7 +14,6 @@ import ui.screen.home.HomeScreen

class IntroViewModel(
private val googleAuthenticationUseCase: GoogleAuthenticationUseCase,
private val metrics: Metrics,
private val sessionManager: SessionManager,
private val analytics: Analytics,
private val scope: CoroutineScope,
Expand All @@ -24,7 +22,10 @@ class IntroViewModel(
@Composable
override fun viewState(): IntroViewState {
LaunchedEffect(Unit) {
metrics.logMetric(name = "intro__view")
analytics.logEvent(
source = Source.Intro,
event = "intro__view"
)
}
return IntroViewState()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import kotlinx.collections.immutable.ImmutableList
sealed interface KpiViewState {
data object Loading : KpiViewState
data class Error(val errMsg: String) : KpiViewState
data class Content(val kpis: ImmutableList<KpiDto>) : KpiViewState
data class Content(
val funnel: ImmutableList<KpiDto>,
val kpis: ImmutableList<KpiDto>
) : KpiViewState
}

sealed interface KpiViewEvent
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,13 @@ class KpiViewModel(

return when (val result = res) {
is Either.Left -> KpiViewState.Error(result.value)
is Either.Right -> KpiViewState.Content(result.value.kpis.toImmutableList())
is Either.Right -> {
val kpisResponse = result.value
KpiViewState.Content(
funnel = kpisResponse.funnel.toImmutableList(),
kpis = kpisResponse.kpis.toImmutableList()
)
}
null -> KpiViewState.Loading
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package ui.screen.kpi.composable

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListScope
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
Expand Down Expand Up @@ -48,9 +50,17 @@ private fun Content(
verticalArrangement = Arrangement.spacedBy(12.dp),
horizontalAlignment = Alignment.Start,
) {
sectionDivider(name = "Funnel")
itemsIndexed(
items = viewState.kpis,
key = { index, item -> "${index}_${item.name}" }
key = { index, item -> "funnel_${index}_${item.name}" }
) { _, item ->
KpiItem(item = item)
}
sectionDivider(name = "KPIs")
itemsIndexed(
items = viewState.kpis,
key = { index, item -> "kpi_${index}_${item.name}" }
) { _, item ->
KpiItem(item = item)
}
Expand All @@ -65,13 +75,29 @@ private fun KpiItem(
Column(modifier = modifier) {
Text(
text = item.name,
style = IvyTheme.typography.b1,
style = MaterialTheme.typography.body1,
fontWeight = FontWeight.SemiBold,
)
Spacer(Modifier.height(4.dp))
Text(
text = item.value,
style = IvyTheme.typography.b2
style = MaterialTheme.typography.body2,
fontWeight = FontWeight.Medium,
color = MaterialTheme.colors.secondary,
)
}
}


private fun LazyListScope.sectionDivider(
name: String,
) {
item(name) {
Spacer(Modifier.height(12.dp))
Text(
text = name,
style = IvyTheme.typography.h1,
color = MaterialTheme.colors.primary,
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import data.SoundRepository
import domain.DeleteUserDataUseCase
import domain.SessionManager
import domain.analytics.Analytics
import domain.analytics.Metrics
import domain.analytics.Source
import ivy.IvyUrls
import kotlinx.coroutines.CoroutineScope
Expand All @@ -27,7 +26,6 @@ class SettingsViewModel(
private val analytics: Analytics,
private val toaster: Toaster,
private val soundRepository: SoundRepository,
private val metrics: Metrics,
) : ComposeViewModel<SettingsViewState, SettingsViewEvent> {
private var soundEnabled by mutableStateOf(true)
private var deleteDialog by mutableStateOf<DeleteDialogViewState?>(null)
Expand Down Expand Up @@ -130,7 +128,7 @@ class SettingsViewModel(
deleteDialog = DeleteDialogViewState(ctaLoading = true)
deleteUserDataUseCase.execute()
deleteDialog = DeleteDialogViewState(ctaLoading = false)
metrics.logMetric(name = "account__deleted")
logEvent(event = "account__deleted")
}
}

Expand Down
Loading
Loading