diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..6a250899
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,105 @@
+name: Krail App CI
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+
+jobs:
+ android:
+ runs-on: ubuntu-latest
+ environment: Firebase
+ timeout-minutes: 60
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup environment variables
+ run: |
+ echo "NSW_TRANSPORT_API_KEY=${{ secrets.NSW_TRANSPORT_API_KEY }}" >> $GITHUB_ENV
+
+ - name: set up JDK
+ uses: actions/setup-java@v4
+ with:
+ distribution: zulu
+ java-version: 21
+
+ - name: Cache Gradle and wrapper
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.gradle/caches
+ ~/.gradle/wrapper
+ key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
+ restore-keys: |
+ ${{ runner.os }}-gradle-
+
+ - name: Make Gradle executable
+ run: chmod +x ./gradlew
+
+ - name: Firebase (Release) - Google Services.json file
+ env:
+ DATA: ${{ secrets.FIREBASE_GOOGLE_SERVICES_JSON_RELEASE }}
+ run: echo $DATA | base64 -di > composeApp/src/androidMain/google-services.json
+
+ - name: Firebase (Debug) - Google Services.json file
+ env:
+ DATA: ${{ secrets.FIREBASE_GOOGLE_SERVICES_JSON_DEBUG }}
+ run: echo $DATA | base64 -di > composeApp/src/androidDebug/google-services.json
+
+# - name: Detekt Checks
+# run: ./gradlew detekt
+
+ - name: Build Debug
+ env:
+ NSW_TRANSPORT_API_KEY: ${{ secrets.NSW_TRANSPORT_API_KEY }}
+ run: ./gradlew :composeApp:assembleDebug test
+
+ - name: Build Release
+ env:
+ NSW_TRANSPORT_API_KEY: ${{ secrets.NSW_TRANSPORT_API_KEY }}
+ run: ./gradlew :composeApp:assembleRelease test
+
+ iOS:
+ runs-on: macos-14
+ environment: Firebase
+ timeout-minutes: 60
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Setup environment variables
+ run: |
+ echo "NSW_TRANSPORT_API_KEY=${{ secrets.NSW_TRANSPORT_API_KEY }}" >> $GITHUB_ENV
+
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: set up JDK
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'temurin'
+ java-version: 21
+
+ - uses: ruby/setup-ruby@v1
+ with:
+ bundler-cache: true
+
+ - run: brew install swiftlint
+
+ - uses: gradle/actions/setup-gradle@v4
+ with:
+ cache-disabled: true
+
+ - name: Build iOS App - Debug (Without Code Signing)
+ env:
+ NSW_TRANSPORT_API_KEY: ${{ secrets.NSW_TRANSPORT_API_KEY }}
+ run: |
+ xcodebuild -project iosApp/iosApp.xcodeproj \
+ -scheme iosApp \
+ -configuration Debug \
+ OBJROOT=$GITHUB_WORKSPACE/build/ios \
+ SYMROOT=$GITHUB_WORKSPACE/build/ios \
+ CODE_SIGN_IDENTITY="" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO \
+ -destination 'platform=iOS Simulator,name=iPhone 12,OS=latest'
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
deleted file mode 100644
index 9e8f882d..00000000
--- a/.github/workflows/ci.yml
+++ /dev/null
@@ -1,57 +0,0 @@
-name: Android CI
-
-on:
- push:
- branches: [ main ]
- pull_request:
- branches: [ main ]
-
-jobs:
- build:
- runs-on: ubuntu-latest
- environment: Firebase
- steps:
- - uses: actions/checkout@v4
- name: Setup environment variables
- env:
- NSW_TRANSPORT_API_KEY: ${{ secrets.NSW_TRANSPORT_API_KEY }}
- run: |
- echo "::set-env name=NSW_TRANSPORT_API_KEY::${{ secrets.NSW_TRANSPORT_API_KEY }}"
-
- - name: set up JDK
- uses: actions/setup-java@v4
- with:
- distribution: zulu
- java-version: 21
-
- - name: Cache Gradle and wrapper
- uses: actions/cache@v4
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
-
- - name: Make Gradle executable
- run: chmod +x ./gradlew
-
- - name: Firebase (Release) - Google Services.json file
- env:
- DATA: ${{ secrets.FIREBASE_GOOGLE_SERVICES_JSON_RELEASE }}
- run: echo $DATA | base64 -di > app/google-services.json
-
- - name: Firebase (Debug) - Google Services.json file
- env:
- DATA: ${{ secrets.FIREBASE_GOOGLE_SERVICES_JSON_DEBUG }}
- run: echo $DATA | base64 -di > app/src/debug/google-services.json
-
- - name: Detekt Checks
- run: ./gradlew detekt
-
- - name: Build Debug
- run: ./gradlew assembleDebug test
-
- - name: Build Release
- run: ./gradlew assembleRelease test
diff --git a/.github/workflows/firebase-app-distribution.yml b/.github/workflows/firebase-app-distribution.yml
deleted file mode 100644
index 9ffcf9af..00000000
--- a/.github/workflows/firebase-app-distribution.yml
+++ /dev/null
@@ -1,54 +0,0 @@
-name: Firebase App Distribution
-
-on:
- pull_request:
- branches:
- - debug-alpha
-
-jobs:
- distribute:
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
- name: Setup environment variables
- env:
- NSW_TRANSPORT_API_KEY: ${{ secrets.NSW_TRANSPORT_API_KEY }}
- run: |
- echo "::set-env name=NSW_TRANSPORT_API_KEY::${{ secrets.NSW_TRANSPORT_API_KEY }}"
-
- - name: set up JDK
- uses: actions/setup-java@v4
- with:
- distribution: zulu
- java-version: 21
-
- - name: Cache Gradle and wrapper
- uses: actions/cache@v4
- with:
- path: |
- ~/.gradle/caches
- ~/.gradle/wrapper
- key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }}
- restore-keys: |
- ${{ runner.os }}-gradle-
-
- - name: Firebase (Debug) - Google Services.json file
- env:
- DATA: ${{ secrets.FIREBASE_GOOGLE_SERVICES_JSON_DEBUG }}
- run: echo $DATA | base64 -di > app/src/debug/google-services.json
-
- - name: Make Gradle executable
- run: chmod +x ./gradlew
-
- - name: Build APK
- run: ./gradlew assembleDebug --no-daemon
-
- - name: Upload to Firebase App Distribution
- env:
- FIREBASE_TOKEN: ${{ secrets.FIREBASE_SERVICE_ACCOUNT_KEY }}
- run: |
- firebase appdistribution:distribute app/build/outputs/apk/debug/app-debug.apk \
- --app ${{ secrets.FIREBASE_APP_ID_DEBUG }} \
- --groups "Friends" \
- --release-notes "Automated release"
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 00000000..a0891f56
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+3.3.4
diff --git a/.xcode-version b/.xcode-version
new file mode 100644
index 00000000..dddffdec
--- /dev/null
+++ b/.xcode-version
@@ -0,0 +1 @@
+15.3
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
deleted file mode 100644
index 9c81af2b..00000000
--- a/app/build.gradle.kts
+++ /dev/null
@@ -1,83 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.application)
- alias(libs.plugins.krail.android.hilt)
- alias(libs.plugins.kotlin.serialization)
-}
-
-android {
- namespace = "xyz.ksharma.krail"
-
- defaultConfig {
- applicationId = "xyz.ksharma.krail"
- versionCode = 12
- versionName = "1.0-alpha03"
-
- testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- buildTypes {
-
- debug {
- applicationIdSuffix = ".debug"
- isDebuggable = true
- ndk {
- isDebuggable = true
- debugSymbolLevel = "FULL"
- }
- }
-
- release {
- isMinifyEnabled = true
- isDebuggable = false
- isShrinkResources = true
- ndk {
- isDebuggable = false
- debugSymbolLevel = "FULL"
- }
- proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
- firebaseCrashlytics {
- nativeSymbolUploadEnabled = true
- }
- }
- }
-
- hilt {
- enableAggregatingTask = true
- }
-}
-
-dependencies {
-
- // Projects
- implementation(projects.core.designSystem)
- implementation(projects.core.network)
- implementation(projects.feature.tripPlanner.network.api)
- implementation(projects.feature.tripPlanner.network.real)
- implementation(projects.feature.tripPlanner.state)
- implementation(projects.feature.tripPlanner.ui)
- implementation(projects.sandook.api)
- implementation(projects.sandook.real)
-
- implementation(libs.activity.compose)
- implementation(libs.compose.foundation)
- implementation(libs.compose.navigation)
- implementation(libs.core.ktx)
- implementation(libs.kotlinx.serialization.json)
- implementation(libs.lifecycle.runtime.ktx)
- implementation(libs.timber)
- implementation(libs.hilt.navigation.compose)
-
- // Firebase
- implementation(platform(libs.firebase.bom))
- implementation(libs.firebase.analytics)
- implementation(libs.firebase.crashlytics)
- implementation(libs.firebase.perf)
-
- // Test
- androidTestImplementation(libs.test.androidxTestExtJunit)
- testImplementation(libs.test.composeUiTestJunit4)
- testImplementation(libs.test.paparazzi)
-}
diff --git a/app/src/.DS_Store b/app/src/.DS_Store
deleted file mode 100644
index ede8a9ca..00000000
Binary files a/app/src/.DS_Store and /dev/null differ
diff --git a/app/src/debug/.gitkeep b/app/src/debug/.gitkeep
deleted file mode 100644
index f2a53523..00000000
--- a/app/src/debug/.gitkeep
+++ /dev/null
@@ -1,2 +0,0 @@
-keep for git
-
diff --git a/app/src/debug/res/drawable/ic_launcher_foreground.xml b/app/src/debug/res/drawable/ic_launcher_foreground.xml
deleted file mode 100644
index 9ea9b179..00000000
--- a/app/src/debug/res/drawable/ic_launcher_foreground.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/KrailApp.kt b/app/src/main/kotlin/xyz/ksharma/krail/KrailApp.kt
deleted file mode 100644
index 059819d5..00000000
--- a/app/src/main/kotlin/xyz/ksharma/krail/KrailApp.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package xyz.ksharma.krail
-
-import androidx.compose.runtime.Composable
-import xyz.ksharma.krail.navigation.KrailNavHost
-
-@Composable
-internal fun KrailApp() {
- KrailNavHost()
-}
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/KrailApplication.kt b/app/src/main/kotlin/xyz/ksharma/krail/KrailApplication.kt
deleted file mode 100644
index 814848fa..00000000
--- a/app/src/main/kotlin/xyz/ksharma/krail/KrailApplication.kt
+++ /dev/null
@@ -1,16 +0,0 @@
-package xyz.ksharma.krail
-
-import android.app.Application
-import dagger.hilt.android.HiltAndroidApp
-import timber.log.Timber
-
-@HiltAndroidApp
-class KrailApplication : Application() {
-
- override fun onCreate() {
- super.onCreate()
- if (BuildConfig.DEBUG) {
- Timber.plant(Timber.DebugTree())
- }
- }
-}
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/MainActivity.kt b/app/src/main/kotlin/xyz/ksharma/krail/MainActivity.kt
deleted file mode 100644
index 12ff4c52..00000000
--- a/app/src/main/kotlin/xyz/ksharma/krail/MainActivity.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package xyz.ksharma.krail
-
-import android.os.Bundle
-import androidx.activity.ComponentActivity
-import androidx.activity.compose.setContent
-import androidx.activity.enableEdgeToEdge
-import dagger.hilt.android.AndroidEntryPoint
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-
-@AndroidEntryPoint
-class MainActivity : ComponentActivity() {
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- enableEdgeToEdge()
- setContent {
- KrailTheme {
- KrailApp()
- }
- }
- }
-}
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
deleted file mode 100644
index 532196b3..00000000
--- a/app/src/main/res/drawable/ic_launcher_background.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
deleted file mode 100644
index 5c71db05..00000000
--- a/app/src/main/res/values/themes.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
diff --git a/app/src/test/java/xyz/ksharma/start/ExampleUnitTest.kt b/app/src/test/java/xyz/ksharma/start/ExampleUnitTest.kt
deleted file mode 100644
index d7eaf556..00000000
--- a/app/src/test/java/xyz/ksharma/start/ExampleUnitTest.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package xyz.ksharma.krail
-
-import org.junit.Test
-
-import org.junit.Assert.*
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * See [testing documentation](http://d.android.com/tools/testing).
- */
-class ExampleUnitTest {
- @Test
- fun addition_isCorrect() {
- assertEquals(4, 2 + 2)
- }
-}
diff --git a/build-logic/convention/build.gradle.kts b/build-logic/convention/build.gradle.kts
deleted file mode 100644
index 0b55affa..00000000
--- a/build-logic/convention/build.gradle.kts
+++ /dev/null
@@ -1,51 +0,0 @@
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-plugins {
- `kotlin-dsl`
-}
-
-group = "xyz.ksharma.buildlogic"
-
-val javaVersion = libs.versions.java.get().toInt()
-
-java {
- sourceCompatibility = JavaVersion.values()[javaVersion - 1]
- targetCompatibility = JavaVersion.values()[javaVersion - 1]
-}
-
-tasks.withType().configureEach {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_17)
- }
-}
-
-dependencies {
- compileOnly(libs.kotlin.gradlePlugin)
- compileOnly(libs.android.gradlePlugin)
-}
-
-gradlePlugin {
- plugins {
- register("application") {
- id = "krail.android.application"
- implementationClass = "ApplicationConventionPlugin"
- }
- register("androidHilt") {
- id = "krail.android.hilt"
- implementationClass = "AndroidHiltConventionPlugin"
- }
- register("androidLibrary") {
- id = "krail.android.library"
- implementationClass = "AndroidLibraryConventionPlugin"
- }
- register("androidLibraryCompose") {
- id = "krail.android.library.compose"
- implementationClass = "AndroidLibraryComposeConventionPlugin"
- }
- register("jvmLibrary") {
- id = "krail.jvm.library"
- implementationClass = "JvmLibraryConventionPlugin"
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidHiltConventionPlugin.kt b/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidHiltConventionPlugin.kt
deleted file mode 100644
index 460f4982..00000000
--- a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidHiltConventionPlugin.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.getByType
-
-class AndroidHiltConventionPlugin : Plugin {
- override fun apply(target: Project) {
- with(target) {
- val libs = extensions.getByType().named("libs")
-
- with(pluginManager) {
- apply("com.google.dagger.hilt.android")
- apply("com.google.devtools.ksp")
- }
-
- dependencies {
- "implementation"(libs.findLibrary("hilt.android").get())
- "ksp"(libs.findLibrary("hilt.compiler").get())
- }
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryComposeConventionPlugin.kt b/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryComposeConventionPlugin.kt
deleted file mode 100644
index 38fecea1..00000000
--- a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryComposeConventionPlugin.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-import com.android.build.gradle.LibraryExtension
-import org.gradle.api.JavaVersion
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.configure
-import org.gradle.kotlin.dsl.getByType
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-@Suppress("UNUSED")
-class AndroidLibraryComposeConventionPlugin : Plugin {
- override fun apply(target: Project) {
- with(target) {
- val libs = extensions.getByType().named("libs")
- val javaVersion = libs.findVersion("java").get().toString().toInt()
- val minSdkVersion = libs.findVersion("minSdk").get().toString().toInt()
- val compileSdkVersion = libs.findVersion("compileSdk").get().toString().toInt()
-
- with(pluginManager) {
- apply("com.android.library")
- apply("org.jetbrains.kotlin.android")
- apply("org.jetbrains.kotlin.plugin.compose")
- }
-
- extensions.configure {
- compileSdk = compileSdkVersion
-
- defaultConfig {
- minSdk = minSdkVersion
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- }
- }
-
- compileOptions {
- sourceCompatibility = JavaVersion.values()[javaVersion - 1]
- targetCompatibility = JavaVersion.values()[javaVersion - 1]
- }
-
- tasks.withType().configureEach {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_17)
-
- freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.FlowPreview")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi")
- }
- }
-
- buildFeatures {
- compose = true
- buildConfig = true
- }
- }
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryConventionPlugin.kt
deleted file mode 100644
index 61072bb4..00000000
--- a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/AndroidLibraryConventionPlugin.kt
+++ /dev/null
@@ -1,65 +0,0 @@
-import com.android.build.gradle.LibraryExtension
-import org.gradle.api.JavaVersion
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.configure
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.getByType
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-@Suppress("UNUSED")
-class AndroidLibraryConventionPlugin : Plugin {
- override fun apply(target: Project) {
- with(target) {
- val libs = extensions.getByType().named("libs")
- val javaVersion = libs.findVersion("java").get().toString().toInt()
- val minSdkVersion = libs.findVersion("minSdk").get().toString().toInt()
- val compileSdkVersion = libs.findVersion("compileSdk").get().toString().toInt()
-
- with(pluginManager) {
- apply("com.android.library")
- apply("org.jetbrains.kotlin.android")
- }
-
- extensions.configure {
- compileSdk = compileSdkVersion
-
- defaultConfig {
- minSdk = minSdkVersion
- }
-
- buildTypes {
- release {
- isMinifyEnabled = false
- }
- }
-
- compileOptions {
- sourceCompatibility = JavaVersion.values()[javaVersion - 1]
- targetCompatibility = JavaVersion.values()[javaVersion - 1]
- }
-
- tasks.withType().configureEach {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_17)
-
- freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.FlowPreview")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi")
- }
- }
-
- buildFeatures {
- buildConfig = true
- }
- }
-
- dependencies {
- "implementation"(libs.findLibrary("timber").get())
- }
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/ApplicationConventionPlugin.kt b/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/ApplicationConventionPlugin.kt
deleted file mode 100644
index 91c488af..00000000
--- a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/ApplicationConventionPlugin.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-import com.android.build.api.dsl.ApplicationExtension
-import org.gradle.api.JavaVersion
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.kotlin.dsl.apply
-import org.gradle.kotlin.dsl.configure
-import org.gradle.kotlin.dsl.dependencies
-import org.gradle.kotlin.dsl.getByType
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-@Suppress("UNUSED")
-class ApplicationConventionPlugin : Plugin {
- override fun apply(target: Project) {
- with(target) {
- val libs = extensions.getByType().named("libs")
- val javaVersion = libs.findVersion("java").get().toString().toInt()
- val minSdkVersion = libs.findVersion("minSdk").get().toString().toInt()
- val targetSdkVersion = libs.findVersion("targetSdk").get().toString().toInt()
- val compileSdkVersion = libs.findVersion("compileSdk").get().toString().toInt()
- val kotlinVersion = libs.findVersion("kotlin").get().toString()
-
- with(pluginManager) {
- apply("com.android.application")
- apply("org.jetbrains.kotlin.android")
- apply("org.jetbrains.kotlin.plugin.compose")
- apply("com.google.gms.google-services")
- apply("com.google.firebase.crashlytics")
- apply("com.google.firebase.firebase-perf")
- }
- extensions.configure {
- compileSdk = compileSdkVersion
-
- defaultConfig {
- minSdk = minSdkVersion
- targetSdk = targetSdkVersion
- vectorDrawables {
- useSupportLibrary = true
- }
- }
-
- compileOptions {
- sourceCompatibility = JavaVersion.values()[javaVersion - 1]
- targetCompatibility = JavaVersion.values()[javaVersion - 1]
- }
-
- tasks.withType().configureEach {
- compilerOptions {
- jvmTarget.set(JvmTarget.JVM_17)
-
- freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.FlowPreview")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi")
- }
- }
-
- buildFeatures {
- compose = true
- buildConfig = true
- }
-
- composeOptions {
- // Kotlin and Compose compiler version is same after K2 is released.
- kotlinCompilerExtensionVersion = kotlinVersion
- }
-
- packaging {
- resources {
- excludes += "/META-INF/{AL2.0,LGPL2.1}"
- }
- }
-
- dependencies {
- "implementation"(libs.findLibrary("timber").get())
- }
- }
- }
- }
-}
diff --git a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/JvmLibraryConventionPlugin.kt b/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/JvmLibraryConventionPlugin.kt
deleted file mode 100644
index 863735c9..00000000
--- a/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/JvmLibraryConventionPlugin.kt
+++ /dev/null
@@ -1,44 +0,0 @@
-import org.gradle.api.JavaVersion
-import org.gradle.api.Plugin
-import org.gradle.api.Project
-import org.gradle.api.artifacts.VersionCatalogsExtension
-import org.gradle.api.plugins.JavaPluginExtension
-import org.gradle.kotlin.dsl.configure
-import org.gradle.kotlin.dsl.getByType
-import org.gradle.kotlin.dsl.provideDelegate
-import org.gradle.kotlin.dsl.withType
-import org.jetbrains.kotlin.gradle.dsl.JvmTarget
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask
-import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
-
-class JvmLibraryConventionPlugin : Plugin {
- override fun apply(target: Project) {
- with(target) {
- val libs = extensions.getByType().named("libs")
- val javaVersion = libs.findVersion("java").get().toString().toInt()
-
- with(pluginManager) {
- apply("org.jetbrains.kotlin.jvm")
- }
-
- extensions.configure {
- sourceCompatibility = JavaVersion.values()[javaVersion - 1]
- targetCompatibility = JavaVersion.values()[javaVersion - 1]
- }
-
- tasks.withType().configureEach {
-
- compilerOptions {
- val warningsAsErrors: String? by project
- allWarningsAsErrors.set(warningsAsErrors.toBoolean())
-
- jvmTarget.set(JvmTarget.JVM_17)
-
- freeCompilerArgs.add("-opt-in=kotlin.RequiresOptIn")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.FlowPreview")
- freeCompilerArgs.add("-opt-in=kotlinx.coroutines.ExperimentalCoroutinesApi")
- }
- }
- }
- }
-}
diff --git a/build-logic/settings.gradle.kts b/build-logic/settings.gradle.kts
deleted file mode 100644
index 62257853..00000000
--- a/build-logic/settings.gradle.kts
+++ /dev/null
@@ -1,14 +0,0 @@
-dependencyResolutionManagement {
- repositories {
- google()
- mavenCentral()
- }
- versionCatalogs {
- create("libs") {
- from(files("../gradle/libs.versions.toml"))
- }
- }
-}
-
-rootProject.name = "build-logic"
-include(":convention")
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 2b049a2e..f6ab05be 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,92 +1,13 @@
-import io.gitlab.arturbosch.detekt.Detekt
// Top-level build file where you can add configuration options common to all sub-projects/modules.
@Suppress("DSL_SCOPE_VIOLATION") // TODO: Remove once KTIJ-19369 is fixed
plugins {
alias(libs.plugins.androidApplication) apply false
alias(libs.plugins.kotlinAndroid) apply false
- alias(libs.plugins.hilt) apply false
alias(libs.plugins.ksp) apply false
alias(libs.plugins.kotlin.serialization) apply false
- alias(libs.plugins.detekt)
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.google.services) apply false
- alias(libs.plugins.firebase.crashlyticsPlugin) apply false
- alias(libs.plugins.firebase.performancePlugin) apply false
-}
-
-subprojects {
- plugins.withId("app.cash.paparazzi") {
- // Defer until afterEvaluate so that testImplementation is created by Android plugin.
- afterEvaluate {
- dependencies.constraints {
- add("testImplementation", "com.google.guava:guava") {
- attributes {
- attribute(
- TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
- objects.named(
- TargetJvmEnvironment::class.java,
- TargetJvmEnvironment.STANDARD_JVM
- )
- )
- }
- because(
- "LayoutLib and sdk-common depend on Guava's -jre published variant." +
- "See https://github.com/cashapp/paparazzi/issues/906."
- )
- }
- }
- }
- }
-}
-true // Needed to make the Suppress annotation work for the plugins block
-
-val excludeFilesDetekt = listOf(
- "**/.gradle/**",
- "**/.idea/**",
- "**/build/**",
- ".github/**",
- "gradle/**",
-)
-
-tasks {
- withType {
- config.setFrom(files("$rootDir/config/detekt/detekt.yaml"))
- baseline.set(file("$rootDir/config/detekt/detekt-baseline.xml"))
-
- autoCorrect = true
- buildUponDefaultConfig = true
- parallel = true
- debug = true
-
- source = files(subprojects.flatMap { subproject ->
- listOf(
- File(subproject.projectDir, "/src/main/kotlin"),
- File(subproject.projectDir, "/src/main/java"),
- File(subproject.projectDir, "/src/debug/kotlin"),
- File(subproject.projectDir, "/src/debug/java"),
- )
- }).asFileTree
-
- excludes.addAll(excludeFilesDetekt)
-
- reports {
- html.required = true
- html.outputLocation.set(file("build/reports/detekt.html"))
- txt.required = true
- md.required = true
- xml.required = false
- sarif.required = false
- }
- }
- project.detekt {
- basePath = rootProject.projectDir.absolutePath
- toolVersion = libs.versions.detekt.get()
- autoCorrect = true
- }
-}
-
-dependencies {
- detektPlugins(libs.detektFormat)
- detektPlugins(libs.detektCompose)
+ alias(libs.plugins.composeMultiplatform) apply false
+ alias(libs.plugins.kotlinMultiplatform) apply false
}
diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
new file mode 100644
index 00000000..eed11ebd
--- /dev/null
+++ b/composeApp/build.gradle.kts
@@ -0,0 +1,113 @@
+import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+android {
+ namespace = "xyz.ksharma.krail"
+
+ defaultConfig {
+ applicationId = "xyz.ksharma.krail"
+ versionCode = 12
+ versionName = "1.0-alpha03"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ vectorDrawables {
+ useSupportLibrary = true
+ }
+ }
+
+ buildTypes {
+
+ debug {
+ applicationIdSuffix = ".debug"
+ isDebuggable = true
+ ndk {
+ isDebuggable = true
+ debugSymbolLevel = "FULL"
+ }
+ }
+
+ release {
+ isMinifyEnabled = true
+ isDebuggable = false
+ isShrinkResources = true
+ ndk {
+ isDebuggable = false
+ debugSymbolLevel = "FULL"
+ }
+ proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
+ }
+ }
+}
+
+plugins {
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.krail.android.application)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.ksp)
+}
+
+kotlin {
+ applyDefaultHierarchyTemplate()
+ androidTarget {
+ @OptIn(ExperimentalKotlinGradlePluginApi::class)
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+ }
+
+ listOf(
+ iosArm64(),
+ iosSimulatorArm64()
+ ).forEach { iosTarget ->
+ iosTarget.binaries.framework {
+ baseName = "KrailApp"
+ isStatic = true
+ }
+ }
+
+ sourceSets {
+ androidMain {
+ dependencies {
+ implementation(compose.preview)
+ implementation(libs.activity.compose)
+ implementation(compose.foundation)
+ implementation(libs.core.ktx)
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.lifecycle.runtime.ktx)
+ api(libs.di.koinAndroid)
+ }
+ }
+
+ commonMain.dependencies {
+ implementation(projects.taj)
+ implementation(projects.sandook)
+ implementation(projects.feature.tripPlanner.network)
+ implementation(projects.feature.tripPlanner.ui)
+ implementation(projects.feature.tripPlanner.state)
+
+ implementation(libs.navigation.compose)
+
+ implementation(compose.runtime)
+ implementation(compose.foundation)
+ implementation(compose.material)
+ implementation(compose.ui)
+ implementation(compose.components.resources)
+ implementation(compose.components.uiToolingPreview)
+ implementation(libs.androidx.lifecycle.runtime.compose)
+
+ implementation(libs.ktor.client.core)
+ implementation(libs.ktor.client.cio)
+ implementation(libs.ktor.client.content.negotiation)
+ implementation(libs.ktor.client.logging)
+ implementation(libs.ktor.serialization.kotlinx.json)
+
+ api(libs.di.koinComposeViewmodel)
+ }
+ }
+}
+
+dependencies {
+ implementation(projects.sandook)
+}
diff --git a/composeApp/src/androidDebug/kotlin/.gitkeep b/composeApp/src/androidDebug/kotlin/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/app/src/main/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
similarity index 100%
rename from app/src/main/AndroidManifest.xml
rename to composeApp/src/androidMain/AndroidManifest.xml
diff --git a/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/KrailApplication.kt b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/KrailApplication.kt
new file mode 100644
index 00000000..20378d13
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/KrailApplication.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail
+
+import android.app.Application
+
+class KrailApplication : Application() {
+
+ override fun onCreate() {
+ super.onCreate()
+ instance = this
+ }
+
+ companion object {
+ var instance : Application? = null
+ }
+}
diff --git a/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/MainActivity.kt b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/MainActivity.kt
new file mode 100644
index 00000000..6c3fafc2
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/MainActivity.kt
@@ -0,0 +1,38 @@
+package xyz.ksharma.krail
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.activity.compose.setContent
+import androidx.activity.enableEdgeToEdge
+import xyz.ksharma.krail.KrailApp
+
+class MainActivity : ComponentActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+
+ enableEdgeToEdge()
+ super.onCreate(savedInstanceState)
+
+/*
+ val applicationComponent = AndroidApplicationComponent.from(this)
+*/
+
+ setContent {
+ KrailApp()
+ }
+ }
+
+ /*
+ private val koinConfig1 = koinConfiguration {
+ androidContext(androidContext = this@MainActivity.applicationContext)
+ modules(androidDbModule)
+ includes(koinConfig)
+ }
+ */
+}
+
+/*
+private fun AndroidApplicationComponent.Companion.from(context: Context): AndroidApplicationComponent {
+ return (context.applicationContext as KrailApplication).component
+}
+*/
diff --git a/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/Platform-android.kt b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/Platform-android.kt
new file mode 100644
index 00000000..0129e774
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/Platform-android.kt
@@ -0,0 +1,9 @@
+package xyz.ksharma.krail
+
+import android.os.Build
+
+class AndroidPlatform : Platform {
+ override val name: String = "Android ${Build.VERSION.SDK_INT}"
+}
+
+actual fun getPlatform(): Platform = AndroidPlatform()
diff --git a/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/di/AppModule.android.kt b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/di/AppModule.android.kt
new file mode 100644
index 00000000..758abdee
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/xyz/ksharma/krail/di/AppModule.android.kt
@@ -0,0 +1,11 @@
+package xyz.ksharma.krail.di
+
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.dsl.koinConfiguration
+import xyz.ksharma.krail.KrailApplication
+
+actual fun nativeConfig() = koinConfiguration {
+ androidLogger()
+ androidContext(KrailApplication.instance ?: error("No Android application context set"))
+}
diff --git a/app/proguard-rules.pro b/composeApp/src/androidMain/proguard-rules.pro
similarity index 100%
rename from app/proguard-rules.pro
rename to composeApp/src/androidMain/proguard-rules.pro
diff --git a/app/src/main/res/color/gradient_background.xml b/composeApp/src/androidMain/res/color/gradient_background.xml
similarity index 100%
rename from app/src/main/res/color/gradient_background.xml
rename to composeApp/src/androidMain/res/color/gradient_background.xml
diff --git a/app/src/debug/res/drawable/ic_launcher_background.xml b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
similarity index 100%
rename from app/src/debug/res/drawable/ic_launcher_background.xml
rename to composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/composeApp/src/androidMain/res/drawable/ic_launcher_foreground.xml
similarity index 100%
rename from app/src/main/res/drawable/ic_launcher_foreground.xml
rename to composeApp/src/androidMain/res/drawable/ic_launcher_foreground.xml
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
rename to composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
similarity index 100%
rename from app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
rename to composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
diff --git a/app/src/main/res/values-night/colors.xml b/composeApp/src/androidMain/res/values-night/colors.xml
similarity index 100%
rename from app/src/main/res/values-night/colors.xml
rename to composeApp/src/androidMain/res/values-night/colors.xml
diff --git a/app/src/main/res/values/colors.xml b/composeApp/src/androidMain/res/values/colors.xml
similarity index 100%
rename from app/src/main/res/values/colors.xml
rename to composeApp/src/androidMain/res/values/colors.xml
diff --git a/app/src/main/res/values/strings.xml b/composeApp/src/androidMain/res/values/strings.xml
similarity index 100%
rename from app/src/main/res/values/strings.xml
rename to composeApp/src/androidMain/res/values/strings.xml
diff --git a/composeApp/src/androidMain/res/values/themes.xml b/composeApp/src/androidMain/res/values/themes.xml
new file mode 100644
index 00000000..931e639d
--- /dev/null
+++ b/composeApp/src/androidMain/res/values/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/app/src/main/res/xml/backup_rules.xml b/composeApp/src/androidMain/res/xml/backup_rules.xml
similarity index 100%
rename from app/src/main/res/xml/backup_rules.xml
rename to composeApp/src/androidMain/res/xml/backup_rules.xml
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/composeApp/src/androidMain/res/xml/data_extraction_rules.xml
similarity index 100%
rename from app/src/main/res/xml/data_extraction_rules.xml
rename to composeApp/src/androidMain/res/xml/data_extraction_rules.xml
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
new file mode 100644
index 00000000..d171a450
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ Krail App
+
diff --git a/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/AppCoroutineDispatchers.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/AppCoroutineDispatchers.kt
new file mode 100644
index 00000000..1b30bfea
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/AppCoroutineDispatchers.kt
@@ -0,0 +1,11 @@
+package xyz.ksharma.krail
+
+import kotlinx.coroutines.CoroutineDispatcher
+
+data class AppCoroutineDispatchers(
+ val io: CoroutineDispatcher,
+ val databaseWrite: CoroutineDispatcher,
+ val databaseRead: CoroutineDispatcher,
+ val computation: CoroutineDispatcher,
+ val main: CoroutineDispatcher,
+)
diff --git a/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailApp.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailApp.kt
new file mode 100644
index 00000000..802d1692
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailApp.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail
+
+import androidx.compose.runtime.Composable
+import org.koin.compose.KoinApplication
+import xyz.ksharma.krail.di.koinConfig
+import xyz.ksharma.krail.taj.theme.KrailTheme
+
+@Composable
+fun KrailApp() {
+ KoinApplication(application = koinConfig) {
+ KrailTheme {
+ KrailNavHost()
+ }
+ }
+}
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/navigation/KrailNavHost.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailNavHost.kt
similarity index 90%
rename from app/src/main/kotlin/xyz/ksharma/krail/navigation/KrailNavHost.kt
rename to composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailNavHost.kt
index bc1e9d92..c5e43cdc 100644
--- a/app/src/main/kotlin/xyz/ksharma/krail/navigation/KrailNavHost.kt
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/KrailNavHost.kt
@@ -1,4 +1,5 @@
-package xyz.ksharma.krail.navigation
+
+package xyz.ksharma.krail
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
@@ -8,20 +9,20 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavOptions
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController
import kotlinx.serialization.Serializable
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.LocalThemeContentColor
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.theme.getForegroundColor
-import xyz.ksharma.krail.design.system.unspecifiedColor
+import org.koin.compose.viewmodel.koinViewModel
import xyz.ksharma.krail.splash.SplashScreen
import xyz.ksharma.krail.splash.SplashViewModel
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.LocalThemeContentColor
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.theme.getForegroundColor
+import xyz.ksharma.krail.taj.unspecifiedColor
import xyz.ksharma.krail.trip.planner.ui.components.hexToComposeColor
import xyz.ksharma.krail.trip.planner.ui.components.toHex
import xyz.ksharma.krail.trip.planner.ui.navigation.SavedTripsRoute
@@ -62,7 +63,7 @@ fun KrailNavHost(modifier: Modifier = Modifier) {
tripPlannerDestinations(navController = navController)
composable {
- val viewModel = hiltViewModel()
+ val viewModel: SplashViewModel = koinViewModel()
val isLoading by viewModel.isLoading.collectAsStateWithLifecycle()
val mode by viewModel.uiState.collectAsStateWithLifecycle()
diff --git a/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/Platform.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/Platform.kt
new file mode 100644
index 00000000..17fe15b1
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/Platform.kt
@@ -0,0 +1,7 @@
+package xyz.ksharma.krail
+
+interface Platform {
+ val name: String
+}
+
+expect fun getPlatform(): Platform
diff --git a/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/di/AppModule.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/di/AppModule.kt
new file mode 100644
index 00000000..48d8d9bb
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/di/AppModule.kt
@@ -0,0 +1,22 @@
+package xyz.ksharma.krail.di
+
+import org.koin.core.module.dsl.viewModelOf
+import org.koin.dsl.KoinAppDeclaration
+import org.koin.dsl.includes
+import org.koin.dsl.koinConfiguration
+import org.koin.dsl.module
+import xyz.ksharma.krail.sandook.di.sandookModule
+import xyz.ksharma.krail.splash.SplashViewModel
+import xyz.ksharma.krail.trip.planner.network.api.di.networkModule
+import xyz.ksharma.krail.trip.planner.ui.di.viewModelsModule
+
+val koinConfig = koinConfiguration {
+ includes(nativeConfig())
+ modules(networkModule + viewModelsModule + sandookModule + splashModule)
+}
+
+val splashModule = module {
+ viewModelOf(::SplashViewModel)
+}
+
+expect fun nativeConfig() : KoinAppDeclaration
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt
similarity index 96%
rename from app/src/main/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt
rename to composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt
index aed7fc57..e10082d7 100644
--- a/app/src/main/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashScreen.kt
@@ -29,15 +29,14 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.TextUnitType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.delay
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import org.jetbrains.compose.ui.tooling.preview.Preview
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun SplashScreen(
@@ -177,7 +176,6 @@ private fun AnimatedLetter(
)
}
-@PreviewLightDark
@Preview
@Composable
private fun PreviewLogo() {
diff --git a/app/src/main/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt
similarity index 75%
rename from app/src/main/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt
rename to composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt
index 05748b94..b6621612 100644
--- a/app/src/main/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt
+++ b/composeApp/src/commonMain/kotlin/xyz/ksharma/krail/splash/SplashViewModel.kt
@@ -2,8 +2,8 @@ package xyz.ksharma.krail.splash
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
@@ -11,17 +11,12 @@ import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import xyz.ksharma.krail.sandook.Sandook
-import xyz.ksharma.krail.sandook.di.SandookFactory
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
-import javax.inject.Inject
-@HiltViewModel
-class SplashViewModel @Inject constructor(
- sandookFactory: SandookFactory,
+class SplashViewModel(
+ private val sandook: Sandook,
) : ViewModel() {
- private val sandook: Sandook = sandookFactory.create(SandookFactory.SandookKey.THEME)
-
private val _uiState: MutableStateFlow = MutableStateFlow(null)
val uiState: MutableStateFlow = _uiState
@@ -33,7 +28,7 @@ class SplashViewModel @Inject constructor(
private fun getThemeTransportMode() {
viewModelScope.launch(Dispatchers.IO) {
- val productClass = sandook.getInt("selectedMode")
+ val productClass = sandook.getProductClass()?.toInt() ?: 0
val mode = TransportMode.toTransportModeType(productClass)
_uiState.value = mode
}
diff --git a/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/MainViewController.kt b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/MainViewController.kt
new file mode 100644
index 00000000..607b0294
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/MainViewController.kt
@@ -0,0 +1,5 @@
+package xyz.ksharma.krail
+
+import androidx.compose.ui.window.ComposeUIViewController
+
+fun MainViewController() = ComposeUIViewController { KrailApp() }
diff --git a/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/Platform.ios.kt b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/Platform.ios.kt
new file mode 100644
index 00000000..77c96dc5
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/Platform.ios.kt
@@ -0,0 +1,10 @@
+package xyz.ksharma.krail
+
+import platform.UIKit.UIDevice
+
+class IOSPlatform : Platform {
+ override val name: String =
+ UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
+}
+
+actual fun getPlatform(): Platform = IOSPlatform()
diff --git a/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/di/AppModule.ios.kt b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/di/AppModule.ios.kt
new file mode 100644
index 00000000..7d51e1d7
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/xyz/ksharma/krail/di/AppModule.ios.kt
@@ -0,0 +1,7 @@
+package xyz.ksharma.krail.di
+
+import org.koin.dsl.koinConfiguration
+
+actual fun nativeConfig() = koinConfiguration {
+ printLogger()
+}
diff --git a/config/detekt/detekt-baseline.xml b/config/detekt/detekt-baseline.xml
deleted file mode 100644
index 64a56649..00000000
--- a/config/detekt/detekt-baseline.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/config/detekt/detekt.yaml b/config/detekt/detekt.yaml
deleted file mode 100644
index a562a979..00000000
--- a/config/detekt/detekt.yaml
+++ /dev/null
@@ -1,408 +0,0 @@
-Compose:
- ComposableAnnotationNaming:
- active: true
- ComposableNaming:
- active: true
- # -- You can optionally disable the checks in this rule for regex matches against the composable name (e.g. molecule presenters)
- # allowedComposableFunctionNames: .*Presenter,.*MoleculePresenter
- ComposableParamOrder:
- active: true
- # -- You can optionally have a list of types to be treated as lambdas (e.g. typedefs or fun interfaces not picked up automatically)
- # treatAsLambda: MyLambdaType
- CompositionLocalAllowlist:
- active: true
- # -- You can optionally define a list of CompositionLocals that are allowed here
- allowedCompositionLocals: LocalTextColor,LocalContentAlpha, LocalTextStyle,LocalContentColor,LocalOnContentColor,LocalKrailTypography,LocalKrailColors,LocalThemeColor,LocalThemeContentColor
- CompositionLocalNaming:
- active: true
- ContentEmitterReturningValues:
- active: true
- # -- You can optionally add your own composables here
- # contentEmitters: MyComposable,MyOtherComposable
- ContentTrailingLambda:
- active: true
- # -- You can optionally have a list of types to be treated as composable lambdas (e.g. typedefs or fun interfaces not picked up automatically)
- # treatAsComposableLambda: MyComposableLambdaType
- DefaultsVisibility:
- active: true
- LambdaParameterInRestartableEffect:
- active: false
- # -- You can optionally have a list of types to be treated as lambdas (e.g. typedefs or fun interfaces not picked up automatically)
- # treatAsLambda: MyLambdaType
- Material2:
- active: true # Opt-in, disabled by default. Turn on if you want to disallow Material 2 usages.
- # -- You can optionally allow parts of it, if you are in the middle of a migration.
- # allowedFromM2: icons.Icons,TopAppBar
- ModifierClickableOrder:
- active: true
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierComposable:
- active: true
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierComposed:
- active: true
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierMissing:
- active: true
- # -- You can optionally control the visibility of which composables to check for here
- # -- Possible values are: `only_public`, `public_and_internal` and `all` (default is `only_public`)
- # checkModifiersForVisibility: only_public
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierNaming:
- active: true
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierNotUsedAtRoot:
- active: true
- # -- You can optionally add your own composables here
- # contentEmitters: MyComposable,MyOtherComposable
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierReused:
- active: true
- # -- You can optionally add your own Modifier types
- # customModifiers: BananaModifier,PotatoModifier
- ModifierWithoutDefault:
- active: true
- MultipleEmitters:
- active: true
- # -- You can optionally add your own composables here that will count as content emitters
- # contentEmitters: MyComposable,MyOtherComposable
- # -- You can add composables here that you don't want to count as content emitters (e.g. custom dialogs or modals)
- # contentEmittersDenylist: MyNonEmitterComposable
- MutableParams:
- active: true
- MutableStateAutoboxing:
- active: true
- MutableStateParam:
- active: true
- ParameterNaming:
- active: true
- # -- You can optionally have a list of types to be treated as composable lambdas (e.g. typedefs or fun interfaces not picked up automatically)
- # treatAsComposableLambda: MyComposableLambdaType
- PreviewAnnotationNaming:
- active: true
- PreviewPublic:
- active: true
- RememberMissing:
- active: true
- RememberContentMissing:
- active: true
- UnstableCollections:
- active: false # Opt-in, disabled by default. Turn on if you want to enforce this (e.g. you have strong skipping disabled)
- ViewModelForwarding:
- active: true
- # -- You can optionally use this rule on things other than types ending in "ViewModel" or "Presenter" (which are the defaults). You can add your own via a regex here:
- # allowedStateHolderNames: .*ViewModel,.*Presenter
- # -- You can optionally add an allowlist for Composable names that won't be affected by this rule
- # allowedForwarding: .*Content,.*FancyStuff
- # -- You can optionally add an allowlist for ViewModel/StateHolder names that won't be affected by this rule
- # allowedForwardingOfTypes: PotatoViewModel,(Apple|Banana)ViewModel,.*FancyViewModel
- ViewModelInjection:
- active: true
- # -- You can optionally add your own ViewModel factories here
- # viewModelFactories: hiltViewModel,potatoViewModel
-
-comments:
- CommentOverPrivateProperty:
- active: true
- UndocumentedPublicClass:
- active: true
- excludes: ['**/*.kt']
- includes: ['**/detekt-api/src/main/**/api/*.kt']
- UndocumentedPublicFunction:
- active: true
- excludes: ['**/*.kt']
- includes: ['**/detekt-api/src/main/**/api/*.kt']
-
-complexity:
- StringLiteralDuplication:
- active: true
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
- threshold: 5
- ignoreAnnotation: true
- excludeStringsWithLessThan5Characters: true
- ignoreStringsRegex: '$^'
- ignoreAnnotated: ['Preview', 'PreviewLightDark', 'PreviewComponent']
- ComplexInterface:
- active: false
- threshold: 10
- includeStaticDeclarations: false
- includePrivateDeclarations: false
- CyclomaticComplexMethod:
- active: true
- ignoreSingleWhenExpression: true
- LargeClass:
- active: true
- excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt']
- MethodOverloading:
- active: true
- TooManyFunctions:
- active: false
- ignoreAnnotatedFunctions: ['Composable']
- excludes: ['**/test/**', '**/functionalTest/**']
- LongMethod:
- active: true
- threshold: 60
- ignoreAnnotated: ['Composable']
- LongParameterList:
- active: false
- ignoreAnnotated: ['Composable', 'Test', 'GET', 'POST']
-
-coroutines:
- active: true
- GlobalCoroutineUsage:
- active: true
- RedundantSuspendModifier:
- active: true
- SleepInsteadOfDelay:
- active: true
- SuspendFunWithFlowReturnType:
- active: true
-
-exceptions:
- InstanceOfCheckForException:
- active: true
- NotImplementedDeclaration:
- active: true
- ObjectExtendsThrowable:
- active: true
- RethrowCaughtException:
- active: true
- ReturnFromFinally:
- active: true
- ThrowingExceptionFromFinally:
- active: true
- ThrowingExceptionInMain:
- active: true
- ThrowingExceptionsWithoutMessageOrCause:
- active: true
- ThrowingNewInstanceOfSameException:
- active: true
-
-formatting:
- active: true
- android: false
- autoCorrect: true
- ContextReceiverMapping:
- active: true
- Filename:
- active: false
- MaximumLineLength:
- active: false
- ParameterListSpacing:
- active: true
- TypeParameterListSpacing:
- active: true
- Indentation:
- active: true
- indentSize: 4
- TrailingCommaOnCallSite:
- active: true
- TrailingCommaOnDeclarationSite:
- active: true
-
-naming:
- ClassNaming:
- ignoreAnnotated: ['org.junit.jupiter.api.Nested']
- FunctionNaming:
- active: true
- excludes: []
- ignoreAnnotated: ['Test', 'ParameterizedTest', 'RepeatedTest', 'TestFactory', 'Composable']
- TopLevelPropertyNaming:
- constantPattern: '[a-z][_A-Za-z0-9]*|[A-Z][_A-Z0-9]*'
- InvalidPackageDeclaration:
- active: true
- excludes: ['**/build-logic/**/*.kt', '**/*.kts']
- NoNameShadowing:
- active: true
- NonBooleanPropertyPrefixedWithIs:
- active: true
- VariableMaxLength:
- active: true
- VariableMinLength:
- active: true
-
-performance:
- SpreadOperator:
- excludes: ['**/test/**', '**/functionalTest/**']
-
-potential-bugs:
- AvoidReferentialEquality:
- active: true
- DontDowncastCollectionTypes:
- active: true
- ElseCaseInsteadOfExhaustiveWhen:
- active: true
- ExitOutsideMain:
- active: false
- HasPlatformType:
- active: true
- IgnoredReturnValue:
- active: true
- ImplicitUnitReturnType:
- active: true
- MapGetWithNotNullAssertionOperator:
- active: true
- UnconditionalJumpStatementInLoop:
- active: true
- UnreachableCatchBlock:
- active: true
- UnsafeCast:
- active: true
- excludes: ['**/test/**', '**/*.Test.kt', '**/*.Spec.kt']
- UselessPostfixExpression:
- active: true
-
-style:
- BracesOnIfStatements:
- active: true
- singleLine: 'consistent'
- multiLine: 'consistent'
- CanBeNonNullable:
- active: true
- CascadingCallWrapping:
- active: false
- ClassOrdering:
- active: true
- CollapsibleIfStatements:
- active: true
- DestructuringDeclarationWithTooManyEntries:
- active: true
- EqualsOnSignatureLine:
- active: true
- ExplicitCollectionElementAccessMethod:
- active: true
- ExplicitItLambdaParameter:
- active: true
- ForbiddenComment:
- active: true
- comments:
- - value: 'FIXME:'
- reason: 'Forbidden FIXME todo marker in comment, please fix the problem.'
- - value: 'STOPSHIP:'
- reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.'
- - value: 'TODO:'
- reason: 'Forbidden TODO todo marker in comment, please do the changes.'
- - value: '@author'
- reason: 'Authors are not recorded in KDoc.'
- - value: '@requiresTypeResolution'
- reason: 'Use @RequiresTypeResolution annotation on the class instead.'
- excludes: ['**/detekt-rules-style/**/ForbiddenComment.kt']
- ForbiddenImport:
- active: true
- imports:
- - value: 'org.assertj.core.api.Assertions'
- reason: 'Import Assertions.assertThat instead.'
- - value: 'org.junit.jupiter.api.Assertions*'
- reason: 'Use AssertJ assertions instead.'
- - value: 'org.junit.jupiter.api.assertAll'
- reason: 'Use AssertJ assertSoftly instead.'
- - value: 'org.junit.jupiter.api.assertThrows'
- reason: 'Use AssertJ assertThatCode { }.isInstanceOf() or assertThatExceptionOfType().isThrownBy { } instead.'
- - value: 'org.junit.jupiter.api.assertDoesNotThrow'
- reason: 'Use AssertJ assertThatCode { }.doesNotThrowAnyException() instead.'
- # These don't have AssertJ alternatives, so just allow them:
- #- value: 'org.junit.jupiter.api.fail'
- #- value: 'org.junit.jupiter.api.assertTimeout'
- #- value: 'org.junit.jupiter.api.assertTimeoutPreemptively'
- - value: 'java.util.stream.*'
- reason: "Use Kotlin's sequences instead."
- ForbiddenMethodCall:
- active: true
- methods:
- - 'kotlin.io.print'
- - 'kotlin.io.println'
- - 'java.net.URL.openStream'
- - 'java.lang.Class.getResourceAsStream'
- - 'java.lang.ClassLoader.getResourceAsStream'
- - 'org.jetbrains.kotlin.diagnostics.DiagnosticUtils.getLineAndColumnInPsiFile'
- ForbiddenVoid:
- active: true
- MagicNumber:
- active: false
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
- ignorePropertyDeclaration: true
- ignoreAnnotation: true
- ignoreEnums: true
- ignoreNumbers:
- - '-1'
- - '0'
- - '1'
- - '2'
- - '100'
- - '1000'
- MandatoryBracesLoops:
- active: true
- MaxLineLength:
- active: true
- excludes: ['**/test/**', '**/*Test.kt', '**/*Spec.kt']
- excludeCommentStatements: true
- autoCorrect: true
- NestedClassesVisibility:
- active: true
- ObjectLiteralToLambda:
- active: true
- PreferToOverPairSyntax:
- active: true
- RedundantExplicitType:
- active: true
- RedundantHigherOrderMapUsage:
- active: true
- RedundantVisibilityModifierRule:
- active: true
- ReturnCount:
- active: true
- excludeGuardClauses: true
- SpacingBetweenPackageAndImports:
- active: true
- TrimMultilineRawString:
- active: true
- UnderscoresInNumericLiterals:
- active: true
- UnnecessaryAnnotationUseSiteTarget:
- active: true
- UnnecessaryBackticks:
- active: true
- UnnecessaryFilter:
- active: true
- UnnecessaryLet:
- active: true
- UnnecessaryInnerClass:
- active: true
- ignoreAnnotated: ['Nested']
- UntilInsteadOfRangeTo:
- active: true
- UnusedImports:
- active: false # formatting already have this rule enabled
- UnusedPrivateMember:
- active: false
- allowedNames: '(_|ignored|expected)'
- UseAnyOrNoneInsteadOfFind:
- active: true
- UseCheckOrError:
- active: true
- UseEmptyCounterpart:
- active: true
- UseIfEmptyOrIfBlank:
- active: true
- UseIsNullOrEmpty:
- active: true
- UseLet:
- active: true
- UseOrEmpty:
- active: true
- UseRequire:
- active: true
- UseRequireNotNull:
- active: true
- VarCouldBeVal:
- active: true
- ignoreAnnotated: ['Parameter']
- WildcardImport:
- active: true
- excludeImports: []
diff --git a/core/coroutines-ext/build.gradle.kts b/core/coroutines-ext/build.gradle.kts
index fb5ba3e0..bc9ade18 100644
--- a/core/coroutines-ext/build.gradle.kts
+++ b/core/coroutines-ext/build.gradle.kts
@@ -1,11 +1,24 @@
plugins {
alias(libs.plugins.krail.android.library)
+ alias(libs.plugins.krail.kotlin.multiplatform)
}
android {
namespace = "xyz.ksharma.krail.coroutines.ext"
}
-dependencies {
- implementation(libs.test.androidxCoreKtx)
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+ iosArm64()
+ iosSimulatorArm64()
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation(libs.kotlinx.coroutines.core)
+ }
+ }
+ }
}
diff --git a/core/coroutines-ext/src/main/kotlin/xyz/ksharma/krail/coroutines/ext/CoroutinesExt.kt b/core/coroutines-ext/src/commonMain/kotlin/xyz/ksharma/krail/coroutines/ext/CoroutinesExt.kt
similarity index 100%
rename from core/coroutines-ext/src/main/kotlin/xyz/ksharma/krail/coroutines/ext/CoroutinesExt.kt
rename to core/coroutines-ext/src/commonMain/kotlin/xyz/ksharma/krail/coroutines/ext/CoroutinesExt.kt
diff --git a/core/date-time/build.gradle.kts b/core/date-time/build.gradle.kts
index 34359049..59230f24 100644
--- a/core/date-time/build.gradle.kts
+++ b/core/date-time/build.gradle.kts
@@ -1,12 +1,33 @@
plugins {
alias(libs.plugins.krail.android.library)
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.compose.compiler)
}
android {
namespace = "xyz.ksharma.krail.core.datetime"
}
-dependencies {
- testImplementation(libs.test.kotlin)
- testImplementation(libs.test.googleTruth)
- implementation(libs.kotlinx.datetime)
+
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+ iosArm64()
+ iosSimulatorArm64()
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation(libs.kotlinx.datetime)
+ implementation(compose.runtime)
+ }
+ }
+
+ commonTest {
+ dependencies {
+ implementation(libs.test.kotlin)
+ }
+ }
+ }
}
diff --git a/core/date-time/src/commonMain/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt b/core/date-time/src/commonMain/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt
new file mode 100644
index 00000000..3af36886
--- /dev/null
+++ b/core/date-time/src/commonMain/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt
@@ -0,0 +1,95 @@
+package xyz.ksharma.krail.core.datetime
+
+import kotlinx.datetime.Clock
+import kotlinx.datetime.Instant
+import kotlinx.datetime.LocalDateTime
+import kotlinx.datetime.TimeZone
+import kotlinx.datetime.toLocalDateTime
+import kotlin.math.absoluteValue
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.minutes
+import kotlin.time.DurationUnit
+
+object DateTimeHelper {
+
+ fun String.formatTo12HourTime(): String {
+ val localDateTime = Instant.parse(this).toLocalDateTime(TimeZone.UTC)
+ val hour = if (localDateTime.hour % 12 == 0) 12 else localDateTime.hour % 12 // Ensure 12-hour format
+ val minute = localDateTime.minute.toString().padStart(2, '0')
+ val amPm = if (localDateTime.hour < 12) "am" else "pm"
+ return "$hour:$minute $amPm"
+ }
+
+ fun String.utcToAEST(): String {
+ val instant = Instant.parse(this)
+ val aestZone = TimeZone.of("Australia/Sydney")
+ val localDateTime = instant.toLocalDateTime(aestZone)
+ return localDateTime.toString()
+ }
+
+ fun String.utcToLocalDateTimeAEST(): LocalDateTime {
+ val instant = Instant.parse(this)
+ val aestZone = TimeZone.of("Australia/Sydney")
+ val localDateTime = instant.toLocalDateTime(aestZone)
+ return localDateTime
+ }
+
+ fun LocalDateTime.toHHMM(): String {
+ val hour = if (this.hour % 12 == 0) 12 else this.hour % 12 // Ensure 12-hour format
+ val minute = this.minute.toString().padStart(2, '0')
+ val amPm = if (this.hour < 12) "AM" else "PM"
+ return "$hour:$minute $amPm"
+ }
+
+ /* fun String.aestToHHMM(): String {
+ val dateTimeString = if (this.length == 16) "$this:00" else this
+ val localDateTime = Instant.parse(dateTimeString).toLocalDateTime(TimeZone.of("Australia/Sydney"))
+ val hour = if (localDateTime.hour % 12 == 0) 12 else localDateTime.hour % 12 // Ensure 12-hour format
+ val minute = localDateTime.minute.toString().padStart(2, '0')
+ val amPm = if (localDateTime.hour < 12) "AM" else "PM"
+ return "$hour:$minute $amPm"
+ }*/
+
+ fun calculateTimeDifferenceFromNow(
+ utcDateString: String,
+ now: Instant = Clock.System.now(),
+ ): Duration {
+ val instant = Instant.parse(utcDateString)
+ return instant - now
+ }
+
+ fun Duration.toGenericFormattedTimeString(): String {
+ val totalMinutes = this.toLong(DurationUnit.MINUTES)
+ val hours = this.toLong(DurationUnit.HOURS)
+ val partialMinutes = totalMinutes - (hours * 60.minutes.inWholeMinutes)
+
+ return when {
+ totalMinutes < 0 -> "${totalMinutes.absoluteValue} ${if (totalMinutes.absoluteValue == 1L) "min" else "mins"} ago"
+ totalMinutes == 0L -> "Now"
+ hours == 1L -> "in ${hours.absoluteValue}h ${partialMinutes.absoluteValue}m"
+ hours >= 2 -> "in ${hours.absoluteValue}h"
+ else -> "in ${totalMinutes.absoluteValue} ${if (totalMinutes.absoluteValue == 1L) "min" else "mins"}"
+ }
+ }
+
+ fun Duration.toFormattedDurationTimeString(): String {
+ val totalMinutes = this.toLong(DurationUnit.MINUTES)
+ val hours = this.toLong(DurationUnit.HOURS)
+ val partialMinutes = totalMinutes - (hours * 60.minutes.inWholeMinutes)
+
+ return when {
+ hours >= 1 && partialMinutes == 0L -> "${hours.absoluteValue}h"
+ hours >= 1 -> "${hours.absoluteValue}h ${partialMinutes.absoluteValue}m"
+ else -> "${totalMinutes.absoluteValue} ${if (totalMinutes.absoluteValue == 1L) "min" else "mins"}"
+ }
+ }
+
+ fun calculateTimeDifference(
+ utcDateString1: String,
+ utcDateString2: String,
+ ): Duration {
+ val instant1 = Instant.parse(utcDateString1)
+ val instant2 = Instant.parse(utcDateString2)
+ return (instant1 - instant2).absoluteValue
+ }
+}
diff --git a/core/date-time/src/commonTest/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt b/core/date-time/src/commonTest/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt
new file mode 100644
index 00000000..d5622640
--- /dev/null
+++ b/core/date-time/src/commonTest/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt
@@ -0,0 +1,91 @@
+package xyz.ksharma.krail.core.datetime
+
+import kotlinx.datetime.Instant
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.formatTo12HourTime
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.toFormattedDurationTimeString
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.toGenericFormattedTimeString
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.utcToAEST
+import kotlin.test.Test
+import kotlin.test.assertEquals
+import kotlin.time.Duration.Companion.minutes
+
+class DateTimeHelperTest {
+
+ @Test
+ fun testCalculateTimeDifferenceFromNow() {
+ val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
+ utcDateString = "2024-10-07T09:00:00Z",
+ now = Instant.parse("2024-10-07T08:20:00Z"),
+ )
+ assertEquals(40L, difference.inWholeMinutes)
+ }
+
+ @Test
+ fun testCalculateTimeDifferenceNextDay() {
+ val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
+ utcDateString = "2024-10-08T09:00:00Z",
+ now = Instant.parse("2024-10-07T08:20:00Z"),
+ )
+ assertEquals(1480L, difference.inWholeMinutes)
+ }
+
+ @Test
+ fun testCalculateTimeDifferencePreviousDay() {
+ val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
+ utcDateString = "2024-10-06T09:00:00Z",
+ now = Instant.parse("2024-10-07T08:20:00Z"),
+ )
+ assertEquals(-1400L, difference.inWholeMinutes)
+ }
+
+ @Test
+ fun testFormatTo12HourTime() {
+ assertEquals("12:00 am", "2024-10-07T00:00:00Z".formatTo12HourTime())
+ assertEquals("1:00 am", "2024-10-07T01:00:00Z".formatTo12HourTime())
+ assertEquals("12:00 pm", "2024-10-07T12:00:00Z".formatTo12HourTime())
+ assertEquals("1:00 pm", "2024-10-07T13:00:00Z".formatTo12HourTime())
+ }
+
+ @Test
+ fun testUtcToAEST() {
+ assertEquals("2024-10-07T11:00:10", "2024-10-07T00:00:10Z".utcToAEST())
+ assertEquals("2024-10-07T12:00", "2024-10-07T01:00:00Z".utcToAEST())
+ assertEquals("2024-10-07T12:00:23", "2024-10-07T01:00:23Z".utcToAEST())
+ }
+
+ @Test
+ fun testToGenericFormattedTimeString() {
+ assertEquals("40 mins ago", (-40).minutes.toGenericFormattedTimeString())
+ assertEquals("Now", 0.minutes.toGenericFormattedTimeString())
+ assertEquals("in 1h 20m", 80.minutes.toGenericFormattedTimeString())
+ assertEquals("in 2h", 120.minutes.toGenericFormattedTimeString())
+ }
+
+ @Test
+ fun testToFormattedDurationTimeString() {
+ assertEquals("1h 20m", 80.minutes.toFormattedDurationTimeString())
+ assertEquals("2h", 120.minutes.toFormattedDurationTimeString())
+ assertEquals("40 mins", 40.minutes.toFormattedDurationTimeString())
+ }
+
+ @Test
+ fun testCalculateTimeDifference() {
+ val difference1 = DateTimeHelper.calculateTimeDifference(
+ utcDateString1 = "2024-10-07T09:00:00Z",
+ utcDateString2 = "2024-10-07T08:20:00Z",
+ )
+ assertEquals(40L, difference1.inWholeMinutes)
+
+ val difference2 = DateTimeHelper.calculateTimeDifference(
+ utcDateString1 = "2024-10-07T09:00:00Z",
+ utcDateString2 = "2024-10-06T09:00:00Z",
+ )
+ assertEquals(1440L, difference2.inWholeMinutes)
+
+ val difference3 = DateTimeHelper.calculateTimeDifference(
+ utcDateString1 = "2024-10-07T09:00:00Z",
+ utcDateString2 = "2024-10-07T09:00:00Z",
+ )
+ assertEquals(0L, difference3.inWholeMinutes)
+ }
+}
diff --git a/core/date-time/src/main/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt b/core/date-time/src/main/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt
deleted file mode 100644
index b917be9a..00000000
--- a/core/date-time/src/main/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelper.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package xyz.ksharma.krail.core.datetime
-
-import kotlinx.datetime.Instant
-import timber.log.Timber
-import java.time.Duration
-import java.time.ZoneId
-import java.time.ZonedDateTime
-import java.time.format.DateTimeFormatter
-import kotlin.math.absoluteValue
-import kotlin.time.Duration.Companion.minutes
-import kotlin.time.DurationUnit
-import kotlin.time.toKotlinDuration
-
-object DateTimeHelper {
-
- fun String.formatTo12HourTime(): String {
- // Parse the string as ZonedDateTime
- val zonedDateTime = ZonedDateTime.parse(this)
-
- // Define the formatter for 12-hour time with AM/PM
- val timeFormatter = DateTimeFormatter.ofPattern("h:mm a")
-
- // Format the ZonedDateTime to 12-hour format
- return zonedDateTime.format(timeFormatter)
- }
-
- /**
- * Convert a date-time string in UTC to AEST time zone.
- * E.g. "2021-08-01T12:00:00Z" -> "2021-08-01T22:00:00+10:00[Australia/Sydney]"
- */
- fun String.utcToAEST(): String {
- // Parse the string as a ZonedDateTime in UTC
- val utcDateTime = ZonedDateTime.parse(this, DateTimeFormatter.ISO_ZONED_DATE_TIME)
-
- // Convert to AEST time zone (UTC+10)
- val aestZoneId = ZoneId.of("Australia/Sydney")
- val aestDateTime = utcDateTime.withZoneSameInstant(aestZoneId)
- return aestDateTime.format(DateTimeFormatter.ISO_DATE_TIME)
- }
-
- /**
- * Converts a date-time string in Australian Eastern Standard Time (AEST)
- * to a string representing the time in hh:mm a format (12-hour format).
- *
- * The input string is expected to be in ISO 8601 format (e.g., "2024-09-24T19:00:00+10:00").
- *
- * @return The time in hh:mm a format (e.g., "07:00 am").
- */
- fun String.aestToHHMM(): String {
- val aestDateTime = ZonedDateTime.parse(this, DateTimeFormatter.ISO_DATE_TIME)
- val timeFormatter = DateTimeFormatter.ofPattern("hh:mm a")
- return aestDateTime.format(timeFormatter)
- }
-
- /**
- * Calculates the time difference between two dates in the UTC format
- * ("2024-09-24T09:00:00Z")
- *
- * @return The time difference between the two dates as a kotlin.time.Duration object.
- */
- fun calculateTimeDifferenceFromNow(
- utcDateString: String,
- now: Instant = kotlinx.datetime.Clock.System.now(), // Get current Instant in UTC
- ): kotlin.time.Duration {
- val instant = Instant.parse(utcDateString) // Parse UTC string to Instant
- return instant - now
- }
-
- fun kotlin.time.Duration.toGenericFormattedTimeString(): String {
- val totalMinutes = this.toLong(DurationUnit.MINUTES)
- val hours = this.toLong(DurationUnit.HOURS)
- val partialMinutes = totalMinutes - (hours * 60.minutes.inWholeMinutes)
-
- val formattedDifference = when {
- totalMinutes < 0 ->
- "${totalMinutes.absoluteValue} " +
- "${if (totalMinutes.absoluteValue == 1L) "min" else "mins"} ago"
-
- totalMinutes == 0L -> "Now"
- hours == 1L -> "in ${hours.absoluteValue}h ${partialMinutes.absoluteValue}m"
- hours >= 2 -> "in ${hours.absoluteValue}h"
- else -> "in ${totalMinutes.absoluteValue} ${if (totalMinutes.absoluteValue == 1L) "min" else "mins"}"
- }
- Timber.d("\t minutes: $partialMinutes, hours: $hours, formattedDifference: $formattedDifference -> originTime")
- return formattedDifference
- }
-
- fun kotlin.time.Duration.toFormattedDurationTimeString(): String {
- val totalMinutes = this.toLong(DurationUnit.MINUTES)
- val hours = this.toLong(DurationUnit.HOURS)
- val partialMinutes = totalMinutes - (hours * 60.minutes.inWholeMinutes)
-
- val formattedDifference = when {
- hours >= 1 -> "${hours.absoluteValue}h ${partialMinutes.absoluteValue}m"
- else -> "${totalMinutes.absoluteValue} ${if (totalMinutes.absoluteValue == 1L) "min" else "mins"}"
- }
- return formattedDifference
- }
-
- fun calculateTimeDifference(
- utcDateString1: String,
- utcDateString2: String,
- ): kotlin.time.Duration {
- // Parse the first UTC date string to a ZonedDateTime
- val dateTime1 = ZonedDateTime.parse(utcDateString1, DateTimeFormatter.ISO_ZONED_DATE_TIME)
-
- // Parse the second UTC date string to a ZonedDateTime
- val dateTime2 = ZonedDateTime.parse(utcDateString2, DateTimeFormatter.ISO_ZONED_DATE_TIME)
-
- // Calculate the duration between the two ZonedDateTime instances
- return Duration.between(dateTime1, dateTime2).toKotlinDuration()
- }
-}
diff --git a/core/date-time/src/test/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt b/core/date-time/src/test/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt
deleted file mode 100644
index 4b35d437..00000000
--- a/core/date-time/src/test/kotlin/xyz/ksharma/krail/core/datetime/DateTimeHelperTest.kt
+++ /dev/null
@@ -1,35 +0,0 @@
-package xyz.ksharma.krail.core.datetime
-
-import com.google.common.truth.Truth.assertThat
-import kotlinx.datetime.Instant
-import kotlin.test.Test
-
-class DateTimeHelperTest {
-
- @Test
- fun testCalculateTimeDifference() {
- val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
- utcDateString = "2024-10-07T09:00:00Z",
- now = Instant.parse("2024-10-07T08:20:00Z"),
- )
- assertThat(difference.inWholeMinutes).isEqualTo(40L)
- }
-
- @Test
- fun testCalculateTimeDifferenceNextDay() {
- val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
- utcDateString = "2024-10-08T09:00:00Z",
- now = Instant.parse("2024-10-07T08:20:00Z"),
- )
- assertThat(difference.inWholeMinutes).isEqualTo(1480L)
- }
-
- @Test
- fun testCalculateTimeDifferencePreviousDay() {
- val difference = DateTimeHelper.calculateTimeDifferenceFromNow(
- utcDateString = "2024-10-06T09:00:00Z",
- now = Instant.parse("2024-10-07T08:20:00Z"),
- )
- assertThat(difference.inWholeMinutes).isEqualTo(-1400L)
- }
-}
diff --git a/core/design-system/README.md b/core/design-system/README.md
deleted file mode 100644
index 9b32f5fa..00000000
--- a/core/design-system/README.md
+++ /dev/null
@@ -1,6 +0,0 @@
-## Important links for documentation
-
-Compose Foundation https://developer.android.com/jetpack/androidx/releases/compose-foundation
-Material 3 Compose Code - https://github.com/androidx/androidx/tree/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3
-Compose Foundation Examples - https://composables.com/foundation/
-Compose Foundation Official Samples - https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:compose/foundation/foundation/samples/src/main/java/androidx/compose/foundation/samples/
diff --git a/core/design-system/build.gradle.kts b/core/design-system/build.gradle.kts
deleted file mode 100644
index 3181d038..00000000
--- a/core/design-system/build.gradle.kts
+++ /dev/null
@@ -1,21 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.library.compose)
- alias(libs.plugins.cash.paparazzi)
-}
-
-android {
- namespace = "xyz.ksharma.krail.design.system"
-}
-
-dependencies {
- api(platform(libs.compose.bom))
- implementation(libs.compose.foundation)
- implementation(libs.compose.ui)
- implementation(libs.compose.ui.graphics)
- api(libs.compose.ui.tooling.preview)
- implementation(libs.compose.material3) // adding for reading code inspiration.
-
- androidTestImplementation(platform(libs.compose.bom))
- debugApi(libs.compose.ui.tooling)
- debugApi(libs.test.composeUiTestManifest)
-}
diff --git a/core/design-system/src/main/kotlin/xyz/.DS_Store b/core/design-system/src/main/kotlin/xyz/.DS_Store
deleted file mode 100644
index 3bebff83..00000000
Binary files a/core/design-system/src/main/kotlin/xyz/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/.DS_Store b/core/design-system/src/main/kotlin/xyz/ksharma/.DS_Store
deleted file mode 100644
index aeb58a8f..00000000
Binary files a/core/design-system/src/main/kotlin/xyz/ksharma/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/.DS_Store b/core/design-system/src/main/kotlin/xyz/ksharma/krail/.DS_Store
deleted file mode 100644
index 5d56e9d7..00000000
Binary files a/core/design-system/src/main/kotlin/xyz/ksharma/krail/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Fab.kt b/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Fab.kt
deleted file mode 100644
index 266b0960..00000000
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Fab.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package xyz.ksharma.krail.design.system.components
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.systemBarsPadding
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.semantics.Role
-import androidx.compose.ui.tooling.preview.PreviewLightDark
-import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentColor
-import xyz.ksharma.krail.design.system.R
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-
-/**
- * FAB is a floating action button that represents the primary action of a screen.
- *
- * @param containerColor The background color of the FAB.
- * @param contentColor The color of the content (e.g., icon) inside the FAB.
- * @param onClick The callback to be invoked when the FAB is clicked.
- * @param modifier The modifier to be applied to the FAB.
- * @param content The composable content to be displayed inside the FAB.
- */
-@Composable
-fun Fab(
- containerColor: Color,
- contentColor: Color,
- onClick: () -> Unit,
- modifier: Modifier = Modifier,
- content: @Composable () -> Unit,
-) {
- Box(
- modifier = modifier
- .fillMaxSize()
- .systemBarsPadding()
- .padding(24.dp)
- .clickable(role = Role.Button, onClick = onClick),
- contentAlignment = Alignment.BottomEnd,
- ) {
- Box(
- modifier = Modifier
- .size(56.dp)
- .background(color = containerColor, shape = CircleShape),
- contentAlignment = Alignment.Center,
- ) {
- CompositionLocalProvider(LocalContentColor provides contentColor) {
- content()
- }
- }
- }
-}
-
-// region Preview
-
-@PreviewLightDark
-@Composable
-private fun PreviewFab() {
- KrailTheme {
- Fab(
- containerColor = KrailTheme.colors.surface,
- contentColor = KrailTheme.colors.onSurface,
- onClick = {},
- ) {
- Image(
- painter = painterResource(R.drawable.star_outline),
- contentDescription = null,
- colorFilter = ColorFilter.tint(color = LocalContentColor.current),
- modifier = Modifier.size(32.dp),
- )
- }
- }
-}
-
-// endregion
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TitleBar.kt b/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TitleBar.kt
deleted file mode 100644
index d582ec47..00000000
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TitleBar.kt
+++ /dev/null
@@ -1,154 +0,0 @@
-package xyz.ksharma.krail.design.system.components
-
-import androidx.compose.foundation.Image
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.heightIn
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.layout.statusBarsPadding
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.clip
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentColor
-import xyz.ksharma.krail.design.system.LocalTextColor
-import xyz.ksharma.krail.design.system.LocalTextStyle
-import xyz.ksharma.krail.design.system.R
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-
-@Composable
-fun TitleBar(
- title: @Composable () -> Unit,
- modifier: Modifier = Modifier,
- navAction: @Composable (() -> Unit)? = null,
- actions: @Composable (() -> Unit)? = null,
-) {
- Row(
- modifier = modifier
- .statusBarsPadding()
- .fillMaxWidth()
- .heightIn(min = 56.dp)
- .padding(end = 16.dp, start = 8.dp)
- .padding(vertical = 4.dp),
- horizontalArrangement = Arrangement.SpaceBetween,
- verticalAlignment = Alignment.CenterVertically,
- ) {
- navAction?.let {
- navAction()
- }
- Row(
- modifier = Modifier
- .weight(1f)
- .padding(start = 10.dp),
- ) {
- CompositionLocalProvider(
- LocalTextColor provides KrailTheme.colors.onSurface,
- LocalTextStyle provides KrailTheme.typography.headlineMedium,
- ) {
- title()
- }
- }
- actions?.let {
- Row(
- modifier = Modifier.padding(start = 16.dp),
- horizontalArrangement = Arrangement.spacedBy(8.dp),
- ) {
- CompositionLocalProvider(
- LocalContentColor provides KrailTheme.colors.onSurface,
- ) {
- actions()
- }
- }
- }
- }
-}
-
-// region Previews
-
-@PreviewComponent
-@Composable
-private fun TitleBarPreview() {
- KrailTheme {
- TitleBar(
- title = {
- Text(text = "Saved Trips Screen Title")
- },
- actions = {
- Image(
- painter = painterResource(id = R.drawable.star_outline),
- contentDescription = null,
- modifier = Modifier.size(24.dp),
- colorFilter = ColorFilter.tint(LocalContentColor.current),
- )
- },
- modifier = Modifier.background(color = KrailTheme.colors.surface),
- )
- }
-}
-
-@Preview
-@Composable
-private fun TitleBarPreviewMultipleActions() {
- KrailTheme {
- TitleBar(
- title = {
- Text(text = "Saved Trips Screen Title")
- },
- actions = {
- Box(
- modifier = Modifier
- .size(40.dp)
- .clip(CircleShape),
- contentAlignment = Alignment.Center,
- ) {
- Image(
- painter = painterResource(id = R.drawable.star_outline),
- contentDescription = null,
- modifier = Modifier.size(24.dp),
- colorFilter = ColorFilter.tint(LocalContentColor.current),
- )
- }
- Box(
- modifier = Modifier
- .size(40.dp)
- .clip(CircleShape),
- contentAlignment = Alignment.Center,
- ) {
- Image(
- painter = painterResource(id = R.drawable.star_outline),
- contentDescription = null,
- modifier = Modifier.size(24.dp),
- colorFilter = ColorFilter.tint(LocalContentColor.current),
- )
- }
- },
- modifier = Modifier.background(color = KrailTheme.colors.surface),
- )
- }
-}
-
-@PreviewComponent
-@Composable
-private fun TitleBarPreviewNoActions() {
- KrailTheme {
- TitleBar(
- title = {
- Text(text = "Saved Trips Screen Title")
- },
- modifier = Modifier.background(color = KrailTheme.colors.surface),
- )
- }
-}
-
-// endregion
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/preview/PreviewComponent.kt b/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/preview/PreviewComponent.kt
deleted file mode 100644
index 69329eb2..00000000
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/preview/PreviewComponent.kt
+++ /dev/null
@@ -1,14 +0,0 @@
-package xyz.ksharma.krail.design.system.preview
-
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
-
-/**
- * A MultiPreview annotation for displaying a component using light and dark themes along with
- * large font size.
- */
-@Retention(AnnotationRetention.BINARY)
-@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION)
-@PreviewLightDark
-@Preview(name = "Large Font", fontScale = 2f)
-annotation class PreviewComponent
diff --git a/core/design-system/src/main/res/drawable/star_filled.xml b/core/design-system/src/main/res/drawable/star_filled.xml
deleted file mode 100644
index 0b4fb8b6..00000000
--- a/core/design-system/src/main/res/drawable/star_filled.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/core/design-system/src/main/res/drawable/star_outline.xml b/core/design-system/src/main/res/drawable/star_outline.xml
deleted file mode 100644
index 8e80be47..00000000
--- a/core/design-system/src/main/res/drawable/star_outline.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
-
diff --git a/core/design-system/src/test/kotlin/xyz/.DS_Store b/core/design-system/src/test/kotlin/xyz/.DS_Store
deleted file mode 100644
index 80a3d64a..00000000
Binary files a/core/design-system/src/test/kotlin/xyz/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/test/kotlin/xyz/ksharma/.DS_Store b/core/design-system/src/test/kotlin/xyz/ksharma/.DS_Store
deleted file mode 100644
index 1677d621..00000000
Binary files a/core/design-system/src/test/kotlin/xyz/ksharma/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/test/kotlin/xyz/ksharma/start/.DS_Store b/core/design-system/src/test/kotlin/xyz/ksharma/start/.DS_Store
deleted file mode 100644
index 122de71f..00000000
Binary files a/core/design-system/src/test/kotlin/xyz/ksharma/start/.DS_Store and /dev/null differ
diff --git a/core/design-system/src/test/kotlin/xyz/ksharma/start/design/.DS_Store b/core/design-system/src/test/kotlin/xyz/ksharma/start/design/.DS_Store
deleted file mode 100644
index 5e966b58..00000000
Binary files a/core/design-system/src/test/kotlin/xyz/ksharma/start/design/.DS_Store and /dev/null differ
diff --git a/core/di/build.gradle.kts b/core/di/build.gradle.kts
deleted file mode 100644
index 9bd1f984..00000000
--- a/core/di/build.gradle.kts
+++ /dev/null
@@ -1,12 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.library)
- alias(libs.plugins.krail.android.hilt)
-}
-
-android {
- namespace = "xyz.ksharma.core.di"
-}
-
-dependencies {
-
-}
diff --git a/core/di/src/main/kotlin/xyz/.DS_Store b/core/di/src/main/kotlin/xyz/.DS_Store
deleted file mode 100644
index 3bebff83..00000000
Binary files a/core/di/src/main/kotlin/xyz/.DS_Store and /dev/null differ
diff --git a/core/di/src/main/kotlin/xyz/ksharma/.DS_Store b/core/di/src/main/kotlin/xyz/ksharma/.DS_Store
deleted file mode 100644
index 0597c575..00000000
Binary files a/core/di/src/main/kotlin/xyz/ksharma/.DS_Store and /dev/null differ
diff --git a/core/di/src/main/kotlin/xyz/ksharma/krail/di/AppDispatchers.kt b/core/di/src/main/kotlin/xyz/ksharma/krail/di/AppDispatchers.kt
deleted file mode 100644
index 43736f21..00000000
--- a/core/di/src/main/kotlin/xyz/ksharma/krail/di/AppDispatchers.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package xyz.ksharma.krail.di
-
-import javax.inject.Qualifier
-
-enum class AppDispatchers {
- Default,
- IO,
-}
-
-@Qualifier
-@Retention(AnnotationRetention.RUNTIME)
-annotation class Dispatcher(val dispatch: AppDispatchers)
diff --git a/core/di/src/main/kotlin/xyz/ksharma/krail/di/CoroutinesModule.kt b/core/di/src/main/kotlin/xyz/ksharma/krail/di/CoroutinesModule.kt
deleted file mode 100644
index a92580c1..00000000
--- a/core/di/src/main/kotlin/xyz/ksharma/krail/di/CoroutinesModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package xyz.ksharma.krail.di
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.SupervisorJob
-
-@Module
-@InstallIn(SingletonComponent::class)
-object CoroutinesModule {
-
- @Provides
- fun provideCoroutineScope(@Dispatcher(AppDispatchers.IO) ioDispatcher: CoroutineDispatcher): CoroutineScope =
- CoroutineScope(context = ioDispatcher + SupervisorJob())
-}
diff --git a/core/di/src/main/kotlin/xyz/ksharma/krail/di/DispatchersModule.kt b/core/di/src/main/kotlin/xyz/ksharma/krail/di/DispatchersModule.kt
deleted file mode 100644
index 654eda4c..00000000
--- a/core/di/src/main/kotlin/xyz/ksharma/krail/di/DispatchersModule.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package xyz.ksharma.krail.di
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.Dispatchers
-
-@Module
-@InstallIn(SingletonComponent::class)
-object DispatchersModule {
-
- @Provides
- @Dispatcher(AppDispatchers.Default)
- fun defaultDispatcher(): CoroutineDispatcher = Dispatchers.Default
-
- @Provides
- @Dispatcher(AppDispatchers.IO)
- fun ioDispatcher(): CoroutineDispatcher = Dispatchers.IO
-}
diff --git a/core/network/build.gradle.kts b/core/network/build.gradle.kts
deleted file mode 100644
index 8c5e92b3..00000000
--- a/core/network/build.gradle.kts
+++ /dev/null
@@ -1,51 +0,0 @@
-import java.util.Properties
-
-plugins {
- alias(libs.plugins.krail.android.library)
- alias(libs.plugins.krail.android.hilt)
- alias(libs.plugins.kotlin.serialization)
- alias(libs.plugins.wire)
-}
-
-// Get local.properties values
-val localProperties = Properties()
-val localPropertiesFile = rootProject.file("local.properties")
-if (localPropertiesFile.exists()) {
- localProperties.load(localPropertiesFile.inputStream())
-}
-val nswTransportApiKey: String = localProperties.getProperty("NSW_TRANSPORT_API_KEY", "")
-
-android {
- namespace = "xyz.ksharma.krail.network"
-
- buildTypes {
- debug {
- buildConfigField("String", "NSW_TRANSPORT_API_KEY", "\"$nswTransportApiKey\"")
- }
-
- release {
- buildConfigField("String", "NSW_TRANSPORT_API_KEY", "\"$nswTransportApiKey\"")
- }
- }
-}
-
-wire {
- kotlin {
- javaInterop = true
- }
- sourcePath {
- srcDir(files("src/main/proto"))
- }
-}
-
-dependencies {
- api(projects.core.di)
- implementation(projects.core.coroutinesExt)
- implementation(libs.test.androidxCoreKtx)
- implementation(libs.kotlinx.serialization.json)
- implementation(platform(libs.okhttp.bom))
- implementation(libs.okhttp)
- implementation(libs.okhttp.logging.interceptor)
- implementation(libs.retrofit)
- implementation(libs.retrofit2.kotlinx.serialization.converter)
-}
diff --git a/core/network/src/main/kotlin/xyz/ksharma/krail/network/ResponseExt.kt b/core/network/src/main/kotlin/xyz/ksharma/krail/network/ResponseExt.kt
deleted file mode 100644
index 6cd709ba..00000000
--- a/core/network/src/main/kotlin/xyz/ksharma/krail/network/ResponseExt.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package xyz.ksharma.krail.network
-
-import retrofit2.Response
-
-/**
- * Processes a Retrofit response and returns a [Result] object.
- *
- * If the response is successful, the body is extracted and wrapped in a [Result.success].
- * If the response is unsuccessful, an [Exception] is created with the error code and wrapped in a [Result.failure].
- *
- * @return A [Result] object containing the response body or an error.
- */
-fun Response.toSafeResult(): Result {
- return if (this.isSuccessful) {
- this.body()?.let { body ->
- Result.success(body)
- } ?: Result.failure(Exception("Response body is null"))
- } else {
- Result.failure(Exception("API call failed with error: ${this.code()}"))
- }
-}
diff --git a/core/network/src/main/kotlin/xyz/ksharma/krail/network/di/NetworkModule.kt b/core/network/src/main/kotlin/xyz/ksharma/krail/network/di/NetworkModule.kt
deleted file mode 100644
index 039e874f..00000000
--- a/core/network/src/main/kotlin/xyz/ksharma/krail/network/di/NetworkModule.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package xyz.ksharma.krail.network.di
-
-import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import kotlinx.serialization.json.Json
-import okhttp3.MediaType.Companion.toMediaType
-import okhttp3.OkHttpClient
-import okhttp3.logging.HttpLoggingInterceptor
-import retrofit2.Retrofit
-import xyz.ksharma.krail.network.BuildConfig
-import xyz.ksharma.krail.network.interceptor.AuthInterceptor
-import java.util.concurrent.TimeUnit
-
-@Module
-@InstallIn(SingletonComponent::class)
-object NetworkModule {
-
- const val BASE_URL = "https://api.transport.nsw.gov.au"
-
- @Provides
- fun provideOkHttpClient(): OkHttpClient {
- val okhttpBuilder = OkHttpClient.Builder()
-
- if (BuildConfig.DEBUG) {
- okhttpBuilder.addInterceptor(
- HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY),
- )
- }
- okhttpBuilder.addInterceptor(AuthInterceptor())
-
- // Add Timeouts
- okhttpBuilder
- .connectTimeout(10, TimeUnit.SECONDS)
- .readTimeout(30, TimeUnit.SECONDS)
- .writeTimeout(30, TimeUnit.SECONDS)
-
- return okhttpBuilder.build()
- }
-
- @Provides
- fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
- val json = Json { ignoreUnknownKeys = true }
-
- val retrofit: Retrofit = Retrofit.Builder()
- .baseUrl(BASE_URL)
- .client(okHttpClient)
- .addConverterFactory(
- json.asConverterFactory(
- "application/json; charset=UTF8".toMediaType(),
- ),
- )
- .build()
- return retrofit
- }
-}
diff --git a/core/network/src/main/kotlin/xyz/ksharma/krail/network/interceptor/AuthInterceptor.kt b/core/network/src/main/kotlin/xyz/ksharma/krail/network/interceptor/AuthInterceptor.kt
deleted file mode 100644
index 3363ebe2..00000000
--- a/core/network/src/main/kotlin/xyz/ksharma/krail/network/interceptor/AuthInterceptor.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package xyz.ksharma.krail.network.interceptor
-
-import okhttp3.Interceptor
-import okhttp3.Request
-import okhttp3.Response
-import xyz.ksharma.krail.network.BuildConfig.NSW_TRANSPORT_API_KEY
-import javax.inject.Singleton
-
-@Singleton
-class AuthInterceptor : Interceptor {
-
- override fun intercept(chain: Interceptor.Chain): Response {
- return chain.proceed(
- Request
- .Builder()
- .header("Authorization", "apikey $NSW_TRANSPORT_API_KEY")
- .header("accept", "application/x-google-protobuf")
- .url(chain.request().url)
- .build(),
- )
- }
-}
diff --git a/feature/trip-planner/network/api/build.gradle.kts b/feature/trip-planner/network/api/build.gradle.kts
deleted file mode 100644
index 4d445b50..00000000
--- a/feature/trip-planner/network/api/build.gradle.kts
+++ /dev/null
@@ -1,17 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.library)
- alias(libs.plugins.krail.android.hilt)
- alias(libs.plugins.kotlin.serialization)
-}
-
-android {
- namespace = "xyz.ksharma.krail.trip.planner.network.api"
-}
-
-dependencies {
- api(projects.core.network)
- implementation(platform(libs.okhttp.bom))
- implementation(libs.okhttp)
- implementation(libs.retrofit)
- implementation(libs.kotlinx.serialization.json)
-}
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/ServiceModule.kt b/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/ServiceModule.kt
deleted file mode 100644
index dc0f6ddc..00000000
--- a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/ServiceModule.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package xyz.ksharma.krail.trip.planner.network.api.di
-
-import dagger.Module
-import dagger.Provides
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import retrofit2.Retrofit
-import xyz.ksharma.krail.trip.planner.network.api.service.TripPlanningService
-import javax.inject.Singleton
-
-@Module
-@InstallIn(SingletonComponent::class)
-object ServiceModule {
-
- @Provides
- @Singleton
- fun provideTripPlanningService(retrofit: Retrofit): TripPlanningService {
- return retrofit.create(TripPlanningService::class.java)
- }
-}
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/repository/TripPlanningRepository.kt b/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/repository/TripPlanningRepository.kt
deleted file mode 100644
index e4cba9d7..00000000
--- a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/repository/TripPlanningRepository.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package xyz.ksharma.krail.trip.planner.network.api.repository
-
-import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
-import xyz.ksharma.krail.trip.planner.network.api.model.StopType
-import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
-import java.time.Instant
-import java.time.ZoneId
-import java.time.format.DateTimeFormatter
-
-interface TripPlanningRepository {
-
- suspend fun stopFinder(
- stopType: StopType = StopType.STOP,
- stopSearchQuery: String,
- ): Result
-
- suspend fun trip(
- originStopId: String,
- destinationStopId: String,
- journeyTime: String? = null,
- ): Result
-}
-
-/**
- * Converts Instant to ITD Time in HHMM 24-hour format.
- * // todo - move to another module for time related functions
- */
-fun Instant.toItdTime(): String {
- val formatter = DateTimeFormatter.ofPattern("HHMM").withZone(ZoneId.of("Australia/Sydney"))
- return formatter.format(this)
-}
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt b/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt
deleted file mode 100644
index f71febd7..00000000
--- a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt
+++ /dev/null
@@ -1,353 +0,0 @@
-package xyz.ksharma.krail.trip.planner.network.api.service
-
-import retrofit2.Response
-import retrofit2.http.GET
-import retrofit2.http.Query
-import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
-import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
-
-/**
- * Swagger: https://opendata.transport.nsw.gov.au/dataset/trip-planner-apis/resource/917c66c3-8123-4a0f-b1b1-b4220f32585d
- */
-interface TripPlanningService {
-
- /**
- * This endpoint returns info about stops that match the search criteria. Matches can be
- * sorted on matchQuality to determine the best matches for the given input, while the best
- * match will be indicated by the isBest value.
- *
- * Provides capability to return all NSW public transport stop, station, wharf,
- * points of interest and known addresses to be used for auto-suggest/auto-complete (to be
- * used with the Trip planner and Departure board APIs).
- */
- @GET("v1/tp/stop_finder")
- suspend fun stopFinder(
- /**
- * Used to set the response data type. This documentation only covers responses that use the JSON format.
- * Setting the outputFormat value to rapidJSON is required to enable JSON output.
- *
- * Available values : rapidJSON
- */
- @Query("outputFormat") outputFormat: String = "rapidJSON",
-
- /**
- * This specifies the type of results expected in the list of returned stops.
- * By specifying `any`, locations of all types can be returned.
- * If you specifically know that you're searching using a coord, specify `coord`.
- * Likewise, if you're using a stop ID or global stop ID as an input, use `stop`
- * for more accurate results.
- *
- * Available values : any, coord, poi, stop
- */
- @Query("type_sf") typeSf: String = "stop",
-
- /**
- * This is the search term that will be used to find locations.
- * To lookup a coordinate, set type_sf to coord, and use the following format:
- * LONGITUDE:LATITUDE:EPSG:4326 (Note that longitude is first). For example, 151.206290:-33.884080:EPSG:4326.
- * To lookup a stop set type_sf to stop and enter the stop id or global stop ID. For example, 10101100
- *
- * Default value : Circular Quay
- */
- @Query("name_sf") nameSf: String,
-
- /**
- * This specifies the format the coordinates are returned in.
- * While other variations are available, the EPSG:4326 format will return the widely-used format.
- *
- * Available values : EPSG:4326
- */
- @Query("coordOutputFormat") coordOutputFormat: String = "EPSG:4326",
-
- /**
- * Including this parameter enables a number of options that result in the stop finder
- * operating in the same way as the Transport for NSW Trip Planner web site.
- *
- * Available values : true
- *
- * Default value : true
- */
- @Query("TfNSWSF") tfNSWSF: String = "true",
-
- /**
- * Indicates which version of the API the caller is expecting for both request and response
- * data. Note that if this version differs
- * from the version listed above then the returned data may not be as expected.
- *
- * Default value : 10.2.1.42
- */
- @Query("version") version: String? = null,
- ): Response
-
- /**
- * This endpoint is used to find a list of journeys between two locations at the specified
- * date and time. For example, if the user is at the Airport and wants to get to Manly using
- * public transport but isn't sure how exactly, this call will tell them exactly which train,
- * bus, ferry or light rail to catch, and between which stops. It is extremely detailed,
- * and includes the the specific path the vehicle(s) will take.
- *
- * Provides capability to provide NSW public transport trip plan options,
- * including walking and driving legs, real-time and Opal fare information.
- */
- @GET("v1/tp/trip")
- suspend fun trip(
- /**
- * Used to set the response data type. This documentation only covers responses that use
- * the JSON format. Setting the outputFormat value to rapidJSON is required to enable JSON output.
- */
- @Query("outputFormat") outputFormat: String = "rapidJSON",
-
- /**
- * This specifies the format the coordinates are returned in. While other variations are
- * available, the EPSG:4326 format will return the widely-used format.
- */
- @Query("coordOutputFormat") coordOutputFormat: String = "EPSG:4326",
-
- /**
- * This value anchors the requested date time. If set to dep, then trips departing after
- * the specified date/time at the specified location are included.
- *
- * If set to arr, then trips arriving before the specified time at its destination stop are included.
- * Works in conjunctions with the [itdDate] and [itdTime] values.
- *
- * "dep" or "arr"
- */
- @Query("depArrMacro") depArrMacro: String,
-
- /**
- * The reference date used when searching trips, in YYYYMMDD format.
- * For instance, 20160901 refers to 1 September 2016. Works in conjunction with the
- * [itdTime] and [depArrMacro] values. If not specified, the current server date is used.
- *
- * Optional, default to null if not provided
- */
- @Query("itdDate") itdDate: String? = null,
-
- /**
- * The reference time used when searching trips, in HHMM 24-hour format.
- * For instance, 2215 refers to 10:15 PM.
- * Works in conjunction with the [itdDate] and [depArrMacro] values.
- *
- * If not specified, the current server time is used.
- *
- * Optional, default to null if not provided
- */
- @Query("itdTime") itdTime: String? = null,
-
- /**
- * This is the type of data specified in the name_origin field. The origin indicates the
- * starting point when searching for journeys.
- * The best way to use the trip planner is to use use any for this field then specify a
- * valid location ID in type_origin, or to use coord
- * in this field and a correctly formatted coordinate in type_origin.
- *
- * Available values : any, coord
- *
- * Default value : any
- */
- @Query("type_origin") typeOrigin: String = "any",
-
- /**
- * This value is used to indicate the starting point when searching for journeys.
- * This value can be one of three things:
- * A valid location/stop ID (for example, 10101100 indicates Central Station - this can be
- * determined using stop_finder).
- *
- * A valid global stop ID (for example, 200060 indicates Central Station - this can be
- * determined using stop_finder) Coordinates in the format LONGITUDE:LATITUDE:EPSG:4326
- * (Note that longitude is first).
- *
- * Default value : 10101331
- */
- @Query("name_origin") nameOrigin: String,
-
- /**
- * This is the type of data specified in the name_destination field. The origin indicates
- * the finishing point when searching for journeys. The best way to use the trip planner
- * is to use use any for this field then specify a valid location ID in type_destination,
- * or to use coord in this field and a correctly formatted coordinate in type_destination.
- *
- * Available values : any, coord
- *
- * Default value : any
- */
- @Query("type_destination") typeDestination: String = "any",
-
- /**
- * his value is used to indicate the finishing point when searching for journeys.
- * This value can be one of three things:
- * A valid location/stop ID (for example, 10101100 indicates Central Station - this can be
- * determined using [stopFinder]).
- *
- * A valid global stop ID (for example, 200060 indicates Central Station - this can be
- * determined using [stopFinder])
- * Coordinates in the format LONGITUDE:LATITUDE:EPSG:4326 (Note that longitude is first).
- *
- * Default value : 10102027
- */
- @Query("name_destination") nameDestination: String, // Destination location or coordinates
-
- /**
- * This parameter indicates the maximum number of trips to returned. Fewer trips may be returned anyway,
- * depending on the available public transport services.
- *
- * Default value : 6
- */
- @Query("calcNumberOfTrips") calcNumberOfTrips: Int = 6,
-
- /**
- * Including this parameter (regardless of its value) ensures that only wheelchair-accessible
- * options are returned.
- *
- * Available values : on
- */
- @Query("wheelchair") wheelchair: String? = null, // Optional, used for wheelchair accessible trips
-
- /**
- * This parameter which means of transport to exclude from the trip plan.
- * To exclude one means,
- * select one of the following: 1 = train, 2 = metro, 4 = light rail, 5 = bus, 7 = coach,
- * 9 = ferry, 11 = school bus.
- * `checkbox` allows you to exclude more than one means of transport when used in conjunction
- * with the exclMOT_ parameters.
- *
- * Available values : checkbox, 1, 2, 4, 5, 7, 9, 11
- */
- @Query("excludedMeans") excludedMeans: String? = null, // Optional, to exclude specific transport modes
-
- /**
- * Excludes train services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_1") exclMOT1: String? = null, // Optional, to exclude trains
-
- /**
- * Excludes metro services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_2") exclMOT2: String? = null, // Optional, to exclude metro
-
- /**
- * Excludes light rail services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_4") exclMOT4: String? = null, // Optional, to exclude light rail
-
- /**
- * Excludes bus services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_5") exclMOT5: String? = null, // Optional, to exclude bus
-
- /**
- * Excludes coach services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_7") exclMOT7: String? = null, // Optional, to exclude bus
-
- /**
- * Excludes ferry services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_9") exclMOT9: String? = null, // Optional, to exclude bus
-
- /**
- * Excludes school bus services from the trip plan. Must be used in conjunction with
- * [excludedMeans]=checkbox
- *
- * Available values : 1
- */
- @Query("exclMOT_11") exclMOT11: String? = null, // Optional, to exclude bus
-
- /**
- * Including this parameter enables a number of options that result in this API call
- * operating in the same way as the Transport for NSW Trip Planner web site,
- * including enabling real-time data.
- *
- * Available values : true
- *
- * Default value : true
- */
- @Query("TfNSWTR") tfNSWTR: String = "true", // Enables real-time data
-
- /**
- * Indicates which version of the API the caller is expecting for both request and response
- * data. Note that if this version differs from the version listed above then the returned
- * data may not be as expected.
- *
- * Default value : 10.2.1.42
- */
- @Query("version") version: String = "10.2.1.42", // API version
-
- /**
- * This parameter activates the options for individual transport. If the parameter is
- * disabled, the parameters concerning individual transport will not be taken into account.
- * possible values are 0 and 1
- *
- * Default value : 1
- */
- @Query("itOptionsActive") itOptionsActive: Int = 1, // Activates individual transport options
-
- /**
- * Activates the calculation of a monomodal trip, i.e., a trip that takes place exclusively
- * with the means of transport , e.g., with bicycle.
- *
- * Note 1: In order to use this parameter, the options for individual transport must be
- * activated with itOptionsActive=1.
- *
- * Note 2: If no monomodal trip with the means of transport is calculated despite the
- * parameter, the maximum time is often set too low. The parameter MaxITTime applies to
- * all means of transport, the parameter MaxITTimeto the means of transport (e.g., MaxITTime107).
- * These parameters are located in the [Parameters] section or are added to it.
- * The configuration can be alternatively overridden by the [maxTime] parameter.
- *
- */
- @Query("computeMonomodalTripBicycle") computeMonomodalTripBicycle: Boolean = false, // Bike only trip
-
- @Query("cycleSpeed") cycleSpeed: Int = 16, // Cycling speed in km/h
-
- @Query("useElevationData") useElevationData: Int = 1, // Takes elevation data into account
-
- @Query("elevFac") elevFac: Int? = null, // Optional elevation factor
- ): Response
-
- /**
- * This endpoint returns a list of departures for a given location based on the date and time
- * specified. This data can be used to display a "upcoming departures" board for a stop.
- *
- * Provides capability to provide NSW public transport departure information
- * from a stop, station or wharf including real-time.
- */
- @GET("v1/tp/departure_mon")
- suspend fun departure()
-
- /**
- * This endpoint returns a list of service alerts or additional information about travelling
- * on the public transport network. This list can be filtered by date, route type, route,
- * operator or stop.
- *
- * Provides capability to display all public transport service status and
- * incident information (as published from the Incident Capture System).
- */
- @GET("v1/tp/add_info")
- suspend fun serviceAlert()
-
- /**
- * When given a specific geographical location, this API finds public transport stops,
- * stations, wharfs and points of interest around that location.
- */
- @GET("v1/tp/coord")
- suspend fun coordinateRequest()
-}
diff --git a/feature/trip-planner/network/build.gradle.kts b/feature/trip-planner/network/build.gradle.kts
new file mode 100644
index 00000000..93e709aa
--- /dev/null
+++ b/feature/trip-planner/network/build.gradle.kts
@@ -0,0 +1,94 @@
+import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
+import com.codingfeline.buildkonfig.compiler.FieldSpec
+
+android {
+ namespace = "xyz.ksharma.krail.trip.planner.network"
+
+ buildTypes {
+ debug {}
+
+ release {}
+ }
+}
+
+plugins {
+ alias(libs.plugins.krail.android.library)
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.ksp)
+ alias(libs.plugins.buildkonfig)
+}
+
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+ listOf(
+ iosX64(),
+ iosArm64(),
+ iosSimulatorArm64()
+ ).forEach {
+ it.binaries.framework {
+ baseName = "network"
+ }
+ }
+
+ sourceSets {
+ androidMain.dependencies {
+ implementation(libs.ktor.client.okhttp)
+ api(libs.di.koinAndroid)
+ }
+
+ commonMain {
+ dependencies {
+
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.ktor.client.core)
+ implementation(libs.ktor.client.auth)
+ implementation(libs.ktor.client.content.negotiation)
+ implementation(libs.ktor.client.logging)
+ implementation(libs.ktor.serialization.kotlinx.json)
+ implementation(libs.kotlinx.datetime)
+ implementation(compose.runtime)
+ implementation(libs.slf4j.simple) // Logging
+
+ api(libs.di.koinComposeViewmodel)
+ }
+ }
+
+ iosMain {
+ dependencies {
+ implementation(libs.ktor.client.darwin)
+ }
+ }
+
+ commonTest {
+ dependencies {
+ implementation(libs.test.kotlin)
+ implementation(libs.test.turbine)
+ implementation(libs.test.kotlinxCoroutineTest)
+ }
+ }
+ }
+}
+
+// READ API KEY
+val localProperties = gradleLocalProperties(rootProject.rootDir, providers)
+val nswTransportApiKey: String = localProperties.getProperty("NSW_TRANSPORT_API_KEY")
+ ?: System.getenv("NSW_TRANSPORT_API_KEY")
+require(nswTransportApiKey.isNotEmpty()) {
+ "Register API key and put in local.properties as `NSW_TRANSPORT_API_KEY`"
+}
+buildkonfig {
+ packageName = "xyz.ksharma.krail.trip.planner.network"
+
+ require(nswTransportApiKey.isNotEmpty()) {
+ "Register API key and put in local.properties as `NSW_TRANSPORT_API_KEY`"
+ }
+
+ defaultConfigs {
+ buildConfigField(FieldSpec.Type.STRING, "NSW_TRANSPORT_API_KEY", nswTransportApiKey)
+ }
+}
diff --git a/feature/trip-planner/network/real/build.gradle.kts b/feature/trip-planner/network/real/build.gradle.kts
deleted file mode 100644
index e1ded5f3..00000000
--- a/feature/trip-planner/network/real/build.gradle.kts
+++ /dev/null
@@ -1,22 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.library)
- alias(libs.plugins.krail.android.hilt)
-}
-
-android {
- namespace = "xyz.ksharma.krail.trip.planner.network.real"
-}
-
-dependencies {
- implementation(projects.core.coroutinesExt)
- implementation(projects.feature.tripPlanner.network.api)
-
- implementation(platform(libs.okhttp.bom))
- implementation(libs.okhttp)
- implementation(libs.retrofit)
-
- testImplementation(libs.test.junit)
- testImplementation(libs.test.turbine)
- testImplementation(libs.test.kotlin)
- testImplementation(libs.test.kotlinxCoroutineTest)
-}
diff --git a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/di/TripPlanningModule.kt b/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/di/TripPlanningModule.kt
deleted file mode 100644
index faa6bbe3..00000000
--- a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/di/TripPlanningModule.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package xyz.ksharma.krail.trip.planner.network.real.di
-
-import dagger.Binds
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import xyz.ksharma.krail.trip.planner.network.api.RateLimiter
-import xyz.ksharma.krail.trip.planner.network.api.repository.TripPlanningRepository
-import xyz.ksharma.krail.trip.planner.network.real.ratelimit.APIRateLimiter
-import xyz.ksharma.krail.trip.planner.network.real.repository.RealTripPlanningRepository
-import javax.inject.Singleton
-
-@Module
-@InstallIn(SingletonComponent::class)
-abstract class TripPlanningModule {
-
- @Binds
- @Singleton
- abstract fun bindTripPlanningRepository(impl: RealTripPlanningRepository): TripPlanningRepository
-
- @Binds
- // This clas should not be Singleton. It should be created per use-case.
- abstract fun bindRateLimiter(impl: APIRateLimiter): RateLimiter
-}
diff --git a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/repository/RealTripPlanningRepository.kt b/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/repository/RealTripPlanningRepository.kt
deleted file mode 100644
index fb05ec4b..00000000
--- a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/repository/RealTripPlanningRepository.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-package xyz.ksharma.krail.trip.planner.network.real.repository
-
-import kotlinx.coroutines.CoroutineDispatcher
-import xyz.ksharma.krail.coroutines.ext.suspendSafeResult
-import xyz.ksharma.krail.di.AppDispatchers
-import xyz.ksharma.krail.di.Dispatcher
-import xyz.ksharma.krail.network.toSafeResult
-import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
-import xyz.ksharma.krail.trip.planner.network.api.model.StopType
-import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
-import xyz.ksharma.krail.trip.planner.network.api.repository.TripPlanningRepository
-import xyz.ksharma.krail.trip.planner.network.api.service.TripPlanningService
-import javax.inject.Inject
-
-class RealTripPlanningRepository @Inject constructor(
- private val tripPlanningService: TripPlanningService,
- @Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
-) : TripPlanningRepository {
-
- override suspend fun stopFinder(
- stopType: StopType,
- stopSearchQuery: String,
- ): Result = suspendSafeResult(ioDispatcher) {
- tripPlanningService.stopFinder(
- typeSf = stopType.type,
- nameSf = stopSearchQuery,
- ).toSafeResult()
- }
-
- override suspend fun trip(
- originStopId: String,
- destinationStopId: String,
- journeyTime: String?,
- ): Result = suspendSafeResult(ioDispatcher) {
- tripPlanningService.trip(
- depArrMacro = "dep",
- nameOrigin = originStopId,
- nameDestination = destinationStopId,
- itdTime = journeyTime,
- ).toSafeResult()
- }
-}
-
-/** Stop Ids
- * Rockdale - 221620
- * Central - 200060
- * TownHall - 200070
- * SevenHills - 214710
- * NewTown - 204210
- */
diff --git a/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/AndroidNetworkComponent.kt b/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/AndroidNetworkComponent.kt
new file mode 100644
index 00000000..22ace500
--- /dev/null
+++ b/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/AndroidNetworkComponent.kt
@@ -0,0 +1,3 @@
+package xyz.ksharma.krail.trip.planner.network.api
+
+//actual fun createNetworkComponent(): NetworkComponent = NetworkComponent::class.create()
diff --git a/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt b/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
new file mode 100644
index 00000000..2d2bedb3
--- /dev/null
+++ b/feature/trip-planner/network/src/androidMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
@@ -0,0 +1,33 @@
+package xyz.ksharma.krail.trip.planner.network.api.service
+
+import io.ktor.client.HttpClient
+import io.ktor.client.engine.okhttp.OkHttp
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.client.plugins.defaultRequest
+import io.ktor.client.plugins.logging.LogLevel
+import io.ktor.client.plugins.logging.Logging
+import io.ktor.http.HttpHeaders
+import io.ktor.serialization.kotlinx.json.json
+import kotlinx.serialization.json.Json
+import xyz.ksharma.krail.trip.planner.network.BuildKonfig
+
+actual fun httpClient(): HttpClient {
+ return HttpClient(OkHttp) {
+ expectSuccess = true
+ install(ContentNegotiation) {
+ json(Json {
+ ignoreUnknownKeys = true
+ isLenient = true
+ prettyPrint = true
+ })
+ }
+ install(Logging) {
+// if(debug) - TODO
+ level = LogLevel.BODY
+ }
+
+ defaultRequest {
+ headers.append(HttpHeaders.Authorization, "apikey ${BuildKonfig.NSW_TRANSPORT_API_KEY}")
+ }
+ }
+}
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/NetworkModule.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/NetworkModule.kt
new file mode 100644
index 00000000..3e6ae788
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/di/NetworkModule.kt
@@ -0,0 +1,17 @@
+package xyz.ksharma.krail.trip.planner.network.api.di
+
+import io.ktor.client.HttpClient
+import org.koin.core.module.dsl.bind
+import org.koin.core.module.dsl.singleOf
+import org.koin.dsl.module
+import xyz.ksharma.krail.trip.planner.network.api.ratelimit.NetworkRateLimiter
+import xyz.ksharma.krail.trip.planner.network.api.ratelimit.RateLimiter
+import xyz.ksharma.krail.trip.planner.network.api.service.RealTripPlanningService
+import xyz.ksharma.krail.trip.planner.network.api.service.TripPlanningService
+import xyz.ksharma.krail.trip.planner.network.api.service.httpClient
+
+val networkModule = module {
+ singleOf(::NetworkRateLimiter) { bind() }
+ single { httpClient() }
+ singleOf(::RealTripPlanningService) { bind() }
+}
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopFinderResponse.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopFinderResponse.kt
similarity index 100%
rename from feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopFinderResponse.kt
rename to feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopFinderResponse.kt
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopType.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopType.kt
similarity index 100%
rename from feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopType.kt
rename to feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/StopType.kt
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/TripResponse.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/TripResponse.kt
similarity index 100%
rename from feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/TripResponse.kt
rename to feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/model/TripResponse.kt
diff --git a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiter.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/NetworkRateLimiter.kt
similarity index 81%
rename from feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiter.kt
rename to feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/NetworkRateLimiter.kt
index b8403aa6..1c677f83 100644
--- a/feature/trip-planner/network/real/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiter.kt
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/NetworkRateLimiter.kt
@@ -1,5 +1,7 @@
-package xyz.ksharma.krail.trip.planner.network.real.ratelimit
+package xyz.ksharma.krail.trip.planner.network.api.ratelimit
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
@@ -7,9 +9,6 @@ import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.update
-import timber.log.Timber
-import xyz.ksharma.krail.trip.planner.network.api.RateLimiter
-import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
@@ -19,7 +18,7 @@ import kotlin.time.Duration.Companion.seconds
*
* Note: This class should not be Singleton. It should be created per use-case.
*/
-class APIRateLimiter @Inject constructor() : RateLimiter {
+class NetworkRateLimiter : RateLimiter {
private val triggerFlow = MutableSharedFlow(replay = 1)
private val isFirstTime = MutableStateFlow(false)
@@ -30,19 +29,20 @@ class APIRateLimiter @Inject constructor() : RateLimiter {
* @param block A suspend function representing the API call to be rate-limited.
* @return A Flow that emits the result of the API call.
*/
+ @OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
override fun rateLimitFlow(block: suspend () -> T): Flow {
return triggerFlow
.debounce {
// First time the block should be executed immediately and subsequent must be rate limited.
val interval = if (isFirstTime.value) rateLimitInterval else 0.milliseconds
- Timber.d("state: ${isFirstTime.value} and interval: $interval")
+ // Timber.d("state: ${isFirstTime.value} and interval: $interval")
interval
}
.flatMapLatest {
- Timber.d("flatmapLatest: Triggered")
+ //Timber.d("flatmapLatest: Triggered")
isFirstTime.update { true } // Mark the first trigger
flow {
- Timber.d("Inside flow -emitting block")
+ // Timber.d("Inside flow -emitting block")
emit(block())
}
}
diff --git a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/RateLimiter.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/RateLimiter.kt
similarity index 92%
rename from feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/RateLimiter.kt
rename to feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/RateLimiter.kt
index 17c172c5..b40d2302 100644
--- a/feature/trip-planner/network/api/src/main/kotlin/xyz/ksharma/krail/trip/planner/network/api/RateLimiter.kt
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/RateLimiter.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.trip.planner.network.api
+package xyz.ksharma.krail.trip.planner.network.api.ratelimit
import kotlinx.coroutines.flow.Flow
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
new file mode 100644
index 00000000..8a2c4a0f
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
@@ -0,0 +1,5 @@
+package xyz.ksharma.krail.trip.planner.network.api.service
+
+import io.ktor.client.HttpClient
+
+expect fun httpClient(): HttpClient
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/RealTripPlanningService.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/RealTripPlanningService.kt
new file mode 100644
index 00000000..c10653ab
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/RealTripPlanningService.kt
@@ -0,0 +1,60 @@
+package xyz.ksharma.krail.trip.planner.network.api.service
+
+import io.ktor.client.HttpClient
+import io.ktor.client.call.body
+import io.ktor.client.request.get
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.IO
+import kotlinx.coroutines.withContext
+import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
+import xyz.ksharma.krail.trip.planner.network.api.model.StopType
+import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
+import xyz.ksharma.krail.trip.planner.network.api.service.stop_finder.StopFinderRequestParams
+import xyz.ksharma.krail.trip.planner.network.api.service.trip.TripRequestParams
+
+class RealTripPlanningService(private val httpClient: HttpClient) : TripPlanningService {
+
+ override suspend fun trip(
+ originStopId: String,
+ destinationStopId: String,
+ ): TripResponse = withContext(Dispatchers.IO) {
+
+ httpClient.get("$NSW_TRANSPORT_BASE_URL/v1/tp/trip") {
+ url {
+ parameters.append(TripRequestParams.nameOrigin, originStopId)
+ parameters.append(TripRequestParams.nameDestination, destinationStopId)
+
+ parameters.append(TripRequestParams.depArrMacro, "dep")
+ parameters.append(TripRequestParams.typeDestination, "any")
+ parameters.append(TripRequestParams.calcNumberOfTrips, "6")
+ parameters.append(TripRequestParams.typeOrigin, "any")
+ parameters.append(TripRequestParams.tfNSWTR, "true")
+ parameters.append(TripRequestParams.version, "10.2.1.42")
+ parameters.append(TripRequestParams.coordOutputFormat, "EPSG:4326")
+ parameters.append(TripRequestParams.itOptionsActive, "1")
+ parameters.append(TripRequestParams.computeMonomodalTripBicycle, "false")
+ parameters.append(TripRequestParams.cycleSpeed, "16")
+ parameters.append(TripRequestParams.useElevationData, "1")
+ parameters.append(TripRequestParams.outputFormat, "rapidJSON")
+ }
+ }.body()
+ }
+
+ override suspend fun stopFinder(
+ stopSearchQuery: String,
+ stopType: StopType,
+ ): StopFinderResponse = withContext(Dispatchers.IO) {
+ httpClient.get("${NSW_TRANSPORT_BASE_URL}/v1/tp/stop_finder") {
+ url {
+ parameters.append(StopFinderRequestParams.nameSf, stopSearchQuery)
+
+ parameters.append(StopFinderRequestParams.typeSf, stopType.type)
+ parameters.append(StopFinderRequestParams.coordOutputFormat, "EPSG:4326")
+ parameters.append(StopFinderRequestParams.outputFormat, "rapidJSON")
+// parameters.append(StopFinderRequestParams.version, "10.2.1.42")
+ parameters.append(StopFinderRequestParams.tfNSWSF, "true")
+ }
+ }.body()
+ }
+
+}
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt
new file mode 100644
index 00000000..ef0e037a
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/TripPlanningService.kt
@@ -0,0 +1,49 @@
+package xyz.ksharma.krail.trip.planner.network.api.service
+
+import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
+import xyz.ksharma.krail.trip.planner.network.api.model.StopType
+import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
+
+/**
+ * Swagger: https://opendata.transport.nsw.gov.au/dataset/trip-planner-apis/resource/917c66c3-8123-4a0f-b1b1-b4220f32585d
+ */
+internal const val NSW_TRANSPORT_BASE_URL = "https://api.transport.nsw.gov.au"
+
+interface TripPlanningService {
+
+ suspend fun trip(originStopId: String, destinationStopId: String): TripResponse
+
+ suspend fun stopFinder(
+ stopSearchQuery: String,
+ stopType: StopType = StopType.STOP,
+ ): StopFinderResponse
+}
+
+
+/**
+ * This endpoint returns a list of departures for a given location based on the date and time
+ * specified. This data can be used to display a "upcoming departures" board for a stop.
+ *
+ * Provides capability to provide NSW public transport departure information
+ * from a stop, station or wharf including real-time.
+ */
+//("v1/tp/departure_mon")
+//suspend fun departure()
+
+/**
+ * This endpoint returns a list of service alerts or additional information about travelling
+ * on the public transport network. This list can be filtered by date, route type, route,
+ * operator or stop.
+ *
+ * Provides capability to display all public transport service status and
+ * incident information (as published from the Incident Capture System).
+ */
+//"v1/tp/add_info")
+//suspend fun serviceAlert()
+
+/**
+ * When given a specific geographical location, this API finds public transport stops,
+ * stations, wharfs and points of interest around that location.
+ */
+//"v1/tp/coord")
+//suspend fun coordinateRequest()
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/stop_finder/StopFinderRequestParams.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/stop_finder/StopFinderRequestParams.kt
new file mode 100644
index 00000000..9405efe3
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/stop_finder/StopFinderRequestParams.kt
@@ -0,0 +1,60 @@
+package xyz.ksharma.krail.trip.planner.network.api.service.stop_finder
+
+internal object StopFinderRequestParams {
+
+ /**
+ * Used to set the response data type. This documentation only covers responses that use the JSON format.
+ * Setting the outputFormat value to rapidJSON is required to enable JSON output.
+ *
+ * Available values : rapidJSON
+ */
+ const val outputFormat: String = "outputFormat"
+
+ /**
+ * This specifies the type of results expected in the list of returned stops.
+ * By specifying `any`, locations of all types can be returned.
+ * If you specifically know that you're searching using a coord, specify `coord`.
+ * Likewise, if you're using a stop ID or global stop ID as an input, use `stop`
+ * for more accurate results.
+ *
+ * Available values : any, coord, poi, stop
+ */
+ const val typeSf: String = "type_sf"
+
+ /**
+ * This is the search term that will be used to find locations.
+ * To lookup a coordinate, set type_sf to coord, and use the following format:
+ * LONGITUDE:LATITUDE:EPSG:4326 (Note that longitude is first). For example, 151.206290:-33.884080:EPSG:4326.
+ * To lookup a stop set type_sf to stop and enter the stop id or global stop ID. For example, 10101100
+ *
+ * Default value : Circular Quay
+ */
+ const val nameSf: String = "name_sf"
+
+ /**
+ * This specifies the format the coordinates are returned in.
+ * While other variations are available, the EPSG:4326 format will return the widely-used format.
+ *
+ * Available values : EPSG:4326
+ */
+ const val coordOutputFormat = "coordOutputFormat" // "EPSG:4326",
+
+ /**
+ * Including this parameter enables a number of options that result in the stop finder
+ * operating in the same way as the Transport for NSW Trip Planner web site.
+ *
+ * Available values : true
+ *
+ * Default value : true
+ */
+ const val tfNSWSF = "TfNSWSF"
+
+ /**
+ * Indicates which version of the API the caller is expecting for both request and response
+ * data. Note that if this version differs
+ * from the version listed above then the returned data may not be as expected.
+ *
+ * Default value : 10.2.1.42
+ */
+ const val version = "version"
+}
diff --git a/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/trip/TripRequestParams.kt b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/trip/TripRequestParams.kt
new file mode 100644
index 00000000..d8d102bd
--- /dev/null
+++ b/feature/trip-planner/network/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/trip/TripRequestParams.kt
@@ -0,0 +1,237 @@
+package xyz.ksharma.krail.trip.planner.network.api.service.trip
+
+internal object TripRequestParams {
+
+ /**
+ * Used to set the response data type. This documentation only covers responses that use
+ * the JSON format. Setting the outputFormat value to rapidJSON is required to enable JSON output.
+ */
+ const val outputFormat: String = "outputFormat"
+
+ /**
+ * This specifies the format the coordinates are returned in. While other variations are
+ * available, the EPSG:4326 format will return the widely-used format.
+ */
+ const val coordOutputFormat: String = "coordOutputFormat"
+
+ /**
+ * This value anchors the requested date time. If set to dep, then trips departing after
+ * the specified date/time at the specified location are included.
+ *
+ * If set to arr, then trips arriving before the specified time at its destination stop are included.
+ * Works in conjunctions with the [itdDate] and [itdTime] values.
+ *
+ * "dep" or "arr"
+ */
+ const val depArrMacro: String = "depArrMacro"
+
+ /**
+ * The reference date used when searching trips, in YYYYMMDD format.
+ * For instance, 20160901 refers to 1 September 2016. Works in conjunction with the
+ * [itdTime] and [depArrMacro] values. If not specified, the current server date is used.
+ *
+ * Optional, default to null if not provided
+ */
+ const val itdDate = "itdDate"
+
+ /**
+ * The reference time used when searching trips, in HHMM 24-hour format.
+ * For instance, 2215 refers to 10:15 PM.
+ * Works in conjunction with the [itdDate] and [depArrMacro] values.
+ *
+ * If not specified, the current server time is used.
+ *
+ * Optional, default to null if not provided
+ */
+ const val itdTime = "itdTime"
+
+ /**
+ * This is the type of data specified in the name_origin field. The origin indicates the
+ * starting point when searching for journeys.
+ * The best way to use the trip planner is to use use any for this field then specify a
+ * valid location ID in type_origin, or to use coord
+ * in this field and a correctly formatted coordinate in type_origin.
+ *
+ * Available values : any, coord
+ *
+ * Default value : any
+ */
+ const val typeOrigin: String = "type_origin"
+
+ /**
+ * This value is used to indicate the starting point when searching for journeys.
+ * This value can be one of three things:
+ * A valid location/stop ID (for example, 10101100 indicates Central Station - this can be
+ * determined using stop_finder).
+ *
+ * A valid global stop ID (for example, 200060 indicates Central Station - this can be
+ * determined using stop_finder) Coordinates in the format LONGITUDE:LATITUDE:EPSG:4326
+ * (Note that longitude is first).
+ *
+ * Default value : 10101331
+ */
+ const val nameOrigin = "name_origin"
+
+ /**
+ * This is the type of data specified in the name_destination field. The origin indicates
+ * the finishing point when searching for journeys. The best way to use the trip planner
+ * is to use use any for this field then specify a valid location ID in type_destination,
+ * or to use coord in this field and a correctly formatted coordinate in type_destination.
+ *
+ * Available values : any, coord
+ *
+ * Default value : any
+ */
+ const val typeDestination: String = "type_destination"
+
+ /**
+ * his value is used to indicate the finishing point when searching for journeys.
+ * This value can be one of three things:
+ * A valid location/stop ID (for example, 10101100 indicates Central Station - this can be
+ * determined using [stopFinder]).
+ *
+ * A valid global stop ID (for example, 200060 indicates Central Station - this can be
+ * determined using [stopFinder])
+ * Coordinates in the format LONGITUDE:LATITUDE:EPSG:4326 (Note that longitude is first).
+ *
+ * Default value : 10102027
+ */
+ const val nameDestination = "name_destination"
+
+ /**
+ * This parameter indicates the maximum number of trips to returned. Fewer trips may be returned anyway,
+ * depending on the available public transport services.
+ *
+ * Default value : 6
+ */
+ const val calcNumberOfTrips = "calcNumberOfTrips"
+
+ /**
+ * Including this parameter (regardless of its value) ensures that only wheelchair-accessible
+ * options are returned.
+ *
+ * Available values : on
+ */
+ const val wheelchair: String = "wheelchair"// Optional, used for wheelchair accessible trips
+
+ /**
+ * This parameter which means of transport to exclude from the trip plan.
+ * To exclude one means,
+ * select one of the following: 1 = train, 2 = metro, 4 = light rail, 5 = bus, 7 = coach,
+ * 9 = ferry, 11 = school bus.
+ * `checkbox` allows you to exclude more than one means of transport when used in conjunction
+ * with the exclMOT_ parameters.
+ *
+ * Available values : checkbox, 1, 2, 4, 5, 7, 9, 11
+ */
+ const val excludedMeans: String =
+ "excludedMeans" // Optional, to exclude specific transport modes
+
+ /**
+ * Excludes train services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT1 = "exclMOT_1" // Optional, to exclude trains
+
+ /**
+ * Excludes metro services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT2 = "exclMOT_2" // Optional, to exclude metro
+
+ /**
+ * Excludes light rail services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT4 = "exclMOT_4" // Optional, to exclude light rail
+
+ /**
+ * Excludes bus services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT5 = "exclMOT_5" // Optional, to exclude bus
+
+
+ /**
+ * Excludes coach services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT7: String = "exclMOT_7" // Optional, to exclude bus
+
+ /**
+ * Excludes ferry services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT9 = "exclMOT_9"// Optional, to exclude bus
+
+ /**
+ * Excludes school bus services from the trip plan. Must be used in conjunction with
+ * [excludedMeans]=checkbox
+ *
+ * Available values : 1
+ */
+ const val exclMOT11 = "exclMOT_11"
+
+ /**
+ * Including this parameter enables a number of options that result in this API call
+ * operating in the same way as the Transport for NSW Trip Planner web site,
+ * including enabling real-time data.
+ *
+ * Available values : true
+ *
+ * Default value : true
+ */
+ const val tfNSWTR = "TfNSWTR"
+
+ /**
+ * Indicates which version of the API the caller is expecting for both request and response
+ * data. Note that if this version differs from the version listed above then the returned
+ * data may not be as expected.
+ *
+ * Default value : 10.2.1.42
+ */
+ const val version = "version"
+
+ /**
+ * This parameter activates the options for individual transport. If the parameter is
+ * disabled, the parameters concerning individual transport will not be taken into account.
+ * possible values are 0 and 1
+ *
+ * Default value : 1
+ */
+ const val itOptionsActive = "itOptionsActive" // Activates individual transport options
+
+ /**
+ * Activates the calculation of a monomodal trip, i.e., a trip that takes place exclusively
+ * with the means of transport , e.g., with bicycle.
+ *
+ * Note 1: In order to use this parameter, the options for individual transport must be
+ * activated with itOptionsActive=1.
+ *
+ * Note 2: If no monomodal trip with the means of transport is calculated despite the
+ * parameter, the maximum time is often set too low. The parameter MaxITTime applies to
+ * all means of transport, the parameter MaxITTimeto the means of transport (e.g., MaxITTime107).
+ * These parameters are located in the [Parameters] section or are added to it.
+ * The configuration can be alternatively overridden by the [maxTime] parameter.
+ *
+ */
+ const val computeMonomodalTripBicycle = "computeMonomodalTripBicycle"
+
+ const val cycleSpeed = "cycleSpeed"
+
+ const val useElevationData = "useElevationData"
+
+ const val elevFac = "elevFac"
+}
diff --git a/feature/trip-planner/network/api/src/test/assets/hige_multiple_legs_trip.json b/feature/trip-planner/network/src/commonTest/assets/hige_multiple_legs_trip.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/hige_multiple_legs_trip.json
rename to feature/trip-planner/network/src/commonTest/assets/hige_multiple_legs_trip.json
diff --git a/feature/trip-planner/network/api/src/test/assets/multiple_legs b/feature/trip-planner/network/src/commonTest/assets/multiple_legs
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/multiple_legs
rename to feature/trip-planner/network/src/commonTest/assets/multiple_legs
diff --git a/feature/trip-planner/network/api/src/test/assets/stop_finder_any.json b/feature/trip-planner/network/src/commonTest/assets/stop_finder_any.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/stop_finder_any.json
rename to feature/trip-planner/network/src/commonTest/assets/stop_finder_any.json
diff --git a/feature/trip-planner/network/api/src/test/assets/stop_finder_stop.json b/feature/trip-planner/network/src/commonTest/assets/stop_finder_stop.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/stop_finder_stop.json
rename to feature/trip-planner/network/src/commonTest/assets/stop_finder_stop.json
diff --git a/feature/trip-planner/network/api/src/test/assets/trip.json b/feature/trip-planner/network/src/commonTest/assets/trip.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/trip.json
rename to feature/trip-planner/network/src/commonTest/assets/trip.json
diff --git a/feature/trip-planner/network/api/src/test/assets/trip_metro_bus.json b/feature/trip-planner/network/src/commonTest/assets/trip_metro_bus.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/trip_metro_bus.json
rename to feature/trip-planner/network/src/commonTest/assets/trip_metro_bus.json
diff --git a/feature/trip-planner/network/api/src/test/assets/trip_occupancy_platform.json b/feature/trip-planner/network/src/commonTest/assets/trip_occupancy_platform.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/trip_occupancy_platform.json
rename to feature/trip-planner/network/src/commonTest/assets/trip_occupancy_platform.json
diff --git a/feature/trip-planner/network/api/src/test/assets/trip_sevenhills_townhall.json b/feature/trip-planner/network/src/commonTest/assets/trip_sevenhills_townhall.json
similarity index 100%
rename from feature/trip-planner/network/api/src/test/assets/trip_sevenhills_townhall.json
rename to feature/trip-planner/network/src/commonTest/assets/trip_sevenhills_townhall.json
diff --git a/feature/trip-planner/network/real/src/test/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiterTest.kt b/feature/trip-planner/network/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/APIRateLimiterTest.kt
similarity index 94%
rename from feature/trip-planner/network/real/src/test/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiterTest.kt
rename to feature/trip-planner/network/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/APIRateLimiterTest.kt
index 64292b24..1e0215ea 100644
--- a/feature/trip-planner/network/real/src/test/kotlin/xyz/ksharma/krail/trip/planner/network/real/ratelimit/APIRateLimiterTest.kt
+++ b/feature/trip-planner/network/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/network/api/ratelimit/APIRateLimiterTest.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.trip.planner.network.real.ratelimit
+package xyz.ksharma.krail.trip.planner.network.api.ratelimit
import app.cash.turbine.test
import kotlinx.coroutines.delay
@@ -9,7 +9,7 @@ import kotlin.time.Duration.Companion.seconds
class APIRateLimiterTest {
- private val rateLimiter = APIRateLimiter()
+ private val rateLimiter = NetworkRateLimiter()
@Test
fun `Given rate limiter When triggered once Then should emit only once within the time interval`() = runTest {
diff --git a/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/IosNetworkComponent.kt b/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/IosNetworkComponent.kt
new file mode 100644
index 00000000..22ace500
--- /dev/null
+++ b/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/IosNetworkComponent.kt
@@ -0,0 +1,3 @@
+package xyz.ksharma.krail.trip.planner.network.api
+
+//actual fun createNetworkComponent(): NetworkComponent = NetworkComponent::class.create()
diff --git a/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt b/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
new file mode 100644
index 00000000..eaa44398
--- /dev/null
+++ b/feature/trip-planner/network/src/iosMain/kotlin/xyz/ksharma/krail/trip/planner/network/api/service/HttpClient.kt
@@ -0,0 +1,33 @@
+package xyz.ksharma.krail.trip.planner.network.api.service
+
+import io.ktor.client.HttpClient
+import io.ktor.client.engine.darwin.Darwin
+import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
+import io.ktor.client.plugins.defaultRequest
+import io.ktor.client.plugins.logging.LogLevel
+import io.ktor.client.plugins.logging.Logging
+import io.ktor.http.HttpHeaders
+import io.ktor.serialization.kotlinx.json.json
+import kotlinx.serialization.json.Json
+import xyz.ksharma.krail.trip.planner.network.BuildKonfig
+
+actual fun httpClient(): HttpClient {
+ return HttpClient(Darwin) {
+ expectSuccess = true
+ install(ContentNegotiation) {
+ json(Json {
+ ignoreUnknownKeys = true
+ isLenient = true
+ prettyPrint = true
+ })
+ }
+ install(Logging) {
+// if(debug) - TODO
+ level = LogLevel.BODY
+ }
+
+ defaultRequest {
+ headers.append(HttpHeaders.Authorization, "apikey ${BuildKonfig.NSW_TRANSPORT_API_KEY}")
+ }
+ }
+}
diff --git a/feature/trip-planner/state/build.gradle.kts b/feature/trip-planner/state/build.gradle.kts
index 4c63505b..6ea023c0 100644
--- a/feature/trip-planner/state/build.gradle.kts
+++ b/feature/trip-planner/state/build.gradle.kts
@@ -1,13 +1,37 @@
plugins {
alias(libs.plugins.krail.android.library)
alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.compose.compiler)
}
android {
namespace = "xyz.ksharma.krail.trip.planner.state"
}
-dependencies {
- implementation(libs.kotlinx.collections.immutable)
- implementation(libs.kotlinx.serialization.json)
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+
+ iosArm64()
+ iosSimulatorArm64()
+
+ java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.majorVersion))
+ }
+ }
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation(libs.kotlinx.collections.immutable)
+ implementation(libs.kotlinx.serialization.json)
+
+ implementation(compose.runtime)
+ }
+ }
+ }
}
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportMode.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportMode.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportMode.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportMode.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportModeLine.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportModeLine.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportModeLine.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/TransportModeLine.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt
similarity index 96%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt
index a6ff02b8..fbc7b7b1 100644
--- a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt
+++ b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/alerts/ServiceAlert.kt
@@ -8,7 +8,7 @@ data class ServiceAlert(
val heading: String,
val message: String,
val priority: ServiceAlertPriority,
-) : java.io.Serializable {
+) {
fun toJsonString() = Json.encodeToString(serializer(), this)
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripUiEvent.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripUiEvent.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripUiEvent.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripUiEvent.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripsState.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripsState.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripsState.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/savedtrip/SavedTripsState.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopState.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopState.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopState.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopState.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopUiEvent.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopUiEvent.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopUiEvent.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/SearchStopUiEvent.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt
similarity index 95%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt
index d90b3b2e..2c8a9a74 100644
--- a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt
+++ b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/searchstop/model/StopItem.kt
@@ -4,7 +4,6 @@ import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.serialization.json.Json
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
-import java.io.Serializable
/**
* Represents a Stop item in the search results when searching for stops.
@@ -15,7 +14,7 @@ data class StopItem(
val stopName: String,
val transportModes: ImmutableSet = persistentSetOf(),
val stopId: String,
-) : Serializable {
+) {
fun toJsonString() = Json.encodeToString(serializer(), this)
@Suppress("ConstPropertyName")
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableState.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableState.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableState.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableState.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableUiEvent.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableUiEvent.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableUiEvent.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/TimeTableUiEvent.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/Trip.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/Trip.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/Trip.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/timetable/Trip.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideEvent.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideEvent.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideEvent.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideEvent.kt
diff --git a/feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideState.kt b/feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideState.kt
similarity index 100%
rename from feature/trip-planner/state/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideState.kt
rename to feature/trip-planner/state/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/state/usualride/UsualRideState.kt
diff --git a/feature/trip-planner/ui/build.gradle.kts b/feature/trip-planner/ui/build.gradle.kts
index 347729bb..3eaab54a 100644
--- a/feature/trip-planner/ui/build.gradle.kts
+++ b/feature/trip-planner/ui/build.gradle.kts
@@ -1,31 +1,58 @@
plugins {
- alias(libs.plugins.krail.android.library.compose)
- alias(libs.plugins.krail.android.hilt)
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.krail.android.library)
alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.ksp)
}
-android {
- namespace = "xyz.ksharma.krail.trip.planner.ui"
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+
+ iosArm64()
+ iosSimulatorArm64()
+
+ java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.majorVersion))
+ }
+ }
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation(projects.taj)
+ implementation(projects.feature.tripPlanner.state)
+ implementation(projects.core.dateTime)
+ implementation(projects.sandook)
+ implementation(projects.feature.tripPlanner.network)
+
+ implementation(compose.foundation)
+ implementation(compose.animation)
+ implementation(compose.ui)
+ implementation(compose.material3)
+ implementation(compose.components.resources)
+ implementation(compose.components.uiToolingPreview)
+
+ implementation(libs.kotlinx.datetime)
+ implementation(libs.kotlinx.collections.immutable)
+ implementation(libs.kotlinx.serialization.json)
+ implementation(libs.navigation.compose)
+ implementation(libs.lifecycle.viewmodel.compose)
+ api(libs.di.koinComposeViewmodel)
+ }
+ }
+ commonTest {
+ dependencies {
+ implementation(libs.test.kotlin)
+ }
+ }
+ }
}
-dependencies {
- implementation(projects.core.dateTime)
- implementation(projects.core.designSystem)
- implementation(projects.feature.tripPlanner.network.api)
- implementation(projects.feature.tripPlanner.state)
- implementation(projects.sandook.api)
-
- implementation(libs.compose.ui)
- implementation(libs.compose.foundation)
- implementation(libs.compose.navigation)
- implementation(libs.hilt.navigation.compose)
- implementation(libs.kotlinx.collections.immutable)
- implementation(libs.kotlinx.serialization.json)
- implementation(libs.timber)
- implementation(libs.kotlinx.datetime)
- implementation(projects.sandook.real)
- implementation(libs.compose.material3)
-
- testImplementation(libs.test.composeUiTestJunit4)
- testImplementation(libs.test.kotlin)
+android {
+ namespace = "xyz.ksharma.krail.trip.planner.ui"
}
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_a11y.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_a11y.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_a11y.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_a11y.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_alert.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_alert.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_alert.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_alert.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_arrow_down.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_arrow_down.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_arrow_down.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_arrow_down.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_arrow_right.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_arrow_right.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_arrow_right.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_arrow_right.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_clock.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_clock.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_clock.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_clock.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_loc.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_loc.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_loc.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_loc.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_location.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_location.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_location.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_location.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_mode_ferry.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_mode_ferry.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_mode_ferry.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_mode_ferry.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_reverse.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_reverse.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_reverse.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_reverse.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_search.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_search.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_search.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_search.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_star.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_star.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_star.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_star.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_star_filled.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_star_filled.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_star_filled.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_star_filled.xml
diff --git a/feature/trip-planner/ui/src/main/res/drawable/ic_walk.xml b/feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_walk.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/drawable/ic_walk.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/drawable/ic_walk.xml
diff --git a/feature/trip-planner/ui/src/main/res/values/strings.xml b/feature/trip-planner/ui/src/commonMain/composeResources/values/strings.xml
similarity index 100%
rename from feature/trip-planner/ui/src/main/res/values/strings.xml
rename to feature/trip-planner/ui/src/commonMain/composeResources/values/strings.xml
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt
similarity index 90%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt
index cb096bdd..b073d7de 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/ContextExt.kt
@@ -1,9 +1,6 @@
package xyz.ksharma.krail.trip.planner.ui
+/*
-import android.app.Activity
-import android.content.Context
-import android.content.ContextWrapper
-import android.graphics.Color
import androidx.activity.ComponentActivity
import androidx.activity.SystemBarStyle
import androidx.activity.enableEdgeToEdge
@@ -39,3 +36,4 @@ internal fun DefaultSystemBarColors() {
onDispose {}
}
}
+*/
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt
similarity index 68%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt
index cc8e7c8a..011554d2 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/AlertsDestination.kt
@@ -1,12 +1,10 @@
package xyz.ksharma.krail.trip.planner.ui.alerts
-import androidx.compose.runtime.LaunchedEffect
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
import kotlinx.collections.immutable.toImmutableSet
-import timber.log.Timber
import xyz.ksharma.krail.trip.planner.ui.navigation.ServiceAlertRoute
import xyz.ksharma.krail.trip.planner.ui.state.alerts.ServiceAlert
@@ -18,15 +16,6 @@ internal fun NavGraphBuilder.alertsDestination(navController: NavHostController)
ServiceAlert.fromJsonString(alertJson)
}.toImmutableSet()
- LaunchedEffect(route.alertsJsonList) {
- route.alertsJsonList.forEach {
- ServiceAlert.fromJsonString(it)?.let { alert ->
- // Timber.d("Alert Heading: ${alert.heading}")
- Timber.d("Alert Message: ${alert.message}")
- }
- }
- }
-
ServiceAlertScreen(serviceAlerts = serviceAlerts, onBackClick = {
navController.popBackStack()
})
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt
similarity index 91%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt
index a99bab90..145c1ccd 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/CollapsibleAlert.kt
@@ -21,13 +21,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.toAdaptiveSize
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.toAdaptiveSize
import xyz.ksharma.krail.trip.planner.ui.components.themeBackgroundColor
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.alerts.ServiceAlert
@@ -91,7 +89,8 @@ fun CollapsibleAlert(
)
}
if (isHtml) {
- HtmlText(serviceAlert.message, onClick = onClick)
+ // TODO - Html Text Component
+ Text(text = serviceAlert.message) // , onClick = onClick
} else {
Text(
text = serviceAlert.message,
@@ -105,8 +104,8 @@ fun CollapsibleAlert(
// region Previews
-@PreviewLightDark
-@Preview(fontScale = 2f)
+
+//@Preview(fontScale = 2f)
@Composable
private fun PreviewCollapsibleAlertCollapsed() {
KrailTheme {
@@ -126,7 +125,7 @@ private fun PreviewCollapsibleAlertCollapsed() {
}
}
-@PreviewLightDark
+
@Composable
private fun PreviewCollapsibleAlertExpanded() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt
similarity index 97%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt
index 7dea84c5..dbdcf5d2 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/HtmlText.kt
@@ -1,4 +1,5 @@
package xyz.ksharma.krail.trip.planner.ui.alerts
+/*
import android.graphics.Typeface
import android.text.method.LinkMovementMethod
@@ -14,11 +15,13 @@ import androidx.compose.ui.text.font.FontSynthesis
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.text.HtmlCompat
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.theme.KrailTheme
+*/
/**
* Reference - https://developer.android.com/codelabs/jetpack-compose-migration#8
- */
+ *//*
+
@Composable
fun HtmlText(html: String, modifier: Modifier = Modifier, onClick: () -> Unit = {}) {
// Remembers the HTML formatted description. Re-executes on a new description
@@ -61,3 +64,4 @@ fun HtmlText(html: String, modifier: Modifier = Modifier, onClick: () -> Unit =
modifier = modifier,
)
}
+*/
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt
similarity index 93%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt
index 44efaf31..5127b987 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/alerts/ServiceAlertScreen.kt
@@ -20,15 +20,13 @@ import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentSetOf
import kotlinx.collections.immutable.toImmutableList
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.components.TitleBar
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.trip.planner.ui.DefaultSystemBarColors
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.components.TitleBar
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.alerts.ServiceAlert
import xyz.ksharma.krail.trip.planner.ui.state.alerts.ServiceAlertPriority
import xyz.ksharma.krail.trip.planner.ui.timetable.ActionButton
@@ -39,7 +37,7 @@ fun ServiceAlertScreen(
modifier: Modifier = Modifier,
onBackClick: () -> Unit = {},
) {
- DefaultSystemBarColors()
+// DefaultSystemBarColors()
Column(
modifier = modifier
@@ -95,7 +93,7 @@ fun ServiceAlertScreen(
}
}
-@Preview
+//@Preview
@Composable
private fun PreviewServiceAlertScreen() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/A11yExt.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/A11yExt.kt
similarity index 100%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/A11yExt.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/A11yExt.kt
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt
similarity index 52%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt
index 996c1460..8609d4bc 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorExt.kt
@@ -5,26 +5,38 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.LocalThemeContentColor
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.LocalThemeContentColor
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
+import kotlin.math.absoluteValue
-/**
- * Converts a hexadecimal color string to a Compose Color object.
- *
- * This function takes a string representing a hexadecimal color code
- * (e.g., "#FF0000" for red) and attempts to convert it into a Compose Color
- * object.
- *
- * @throws IllegalArgumentException if the provided string is not a valid
- * hexadecimal color code. A valid code must start with "#" followed by
- * either 6 or 8 hexadecimal digits (0-9, A-F, a-f).
- *
- * @return A Compose Color object representing the provided hex color code.
- */
fun String.hexToComposeColor(): Color {
- require(this.isValidHexColorCode()) { "Invalid hex color code: $this" }
- return Color(android.graphics.Color.parseColor(this))
+ require(isValidHexColorCode()) {
+ "Invalid hex color code: $this. Hex color codes must be in the format #RRGGBB or #AARRGGBB."
+ }
+
+ // Remove the leading '#' if present
+ val hex = removePrefix("#")
+
+ // Parse the hex value
+ return when (hex.length) {
+ 6 -> {
+ // If the string is in the format RRGGBB, add full opacity (FF) at the start
+ val r = hex.substring(0, 2).toInt(16)
+ val g = hex.substring(2, 4).toInt(16)
+ val b = hex.substring(4, 6).toInt(16)
+ Color(red = r / 255f, green = g / 255f, blue = b / 255f)
+ }
+ 8 -> {
+ // If the string is in the format AARRGGBB
+ val a = hex.substring(0, 2).toInt(16)
+ val r = hex.substring(2, 4).toInt(16)
+ val g = hex.substring(4, 6).toInt(16)
+ val b = hex.substring(6, 8).toInt(16)
+ Color(alpha = a / 255f, red = r / 255f, green = g / 255f, blue = b / 255f)
+ }
+ else -> throw IllegalArgumentException("Invalid hex color format. Use #RRGGBB or #AARRGGBB.")
+ }
}
/**
@@ -80,26 +92,17 @@ internal fun themeContentColor(): Color {
*
* @return A string representing the hexadecimal color code (e.g., "#FF0000" for red).
*/
-@Suppress("ImplicitDefaultLocale")
fun Color.toHex(): String {
val red = (this.red * 255).toInt()
val green = (this.green * 255).toInt()
val blue = (this.blue * 255).toInt()
val alpha = (this.alpha * 255).toInt()
- return String.format("#%02X%02X%02X%02X", alpha, red, green, blue)
+ return "#${alpha.toHex()}${red.toHex()}${green.toHex()}${blue.toHex()}"
}
-/**
- * The default light scrim, as defined by androidx and the platform:
- * https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:activity/activity/src/main/java/androidx/activity/EdgeToEdge.kt;l=35-38;drc=27e7d52e8604a080133e8b842db10c89b4482598
- */
-val lightScrim = android.graphics.Color.argb(0xe6, 0xFF, 0xFF, 0xFF)
-
-/**
- * The default dark scrim, as defined by androidx and the platform:
- * https://cs.android.com/androidx/platform/frameworks/support/+/androidx-main:activity/activity/src/main/java/androidx/activity/EdgeToEdge.kt;l=40-44;drc=27e7d52e8604a080133e8b842db10c89b4482598
- */
-val darkScrim = android.graphics.Color.argb(0x80, 0x1b, 0x1b, 0x1b)
+private fun Int.toHex(): String {
+ return this.toString(16).padStart(2, '0').uppercase()
+}
/**
* Update the theme color to make text more readable on top of it.
@@ -115,26 +118,63 @@ val darkScrim = android.graphics.Color.argb(0x80, 0x1b, 0x1b, 0x1b)
*
* @return The brightened color in ARGB format
*/
-private fun brightenColor(color: Int, factor: Float = 0.2f): Int {
- // Convert the color to RGB components
- val red = android.graphics.Color.red(color) / 255f
- val green = android.graphics.Color.green(color) / 255f
- val blue = android.graphics.Color.blue(color) / 255f
-
- // Convert RGB to HSL
- val hsl = FloatArray(3)
- android.graphics.Color.RGBToHSV(
- (red * 255).toInt(),
- (green * 255).toInt(),
- (blue * 255).toInt(),
- hsl,
- )
-
- // Adjust lightness (value) within bounds
- hsl[2] = (hsl[2] + factor).coerceIn(0f, 1f)
-
- // Convert back to RGB
- return android.graphics.Color.HSVToColor(hsl)
+fun brightenColor(color: Int, factor: Float = 0.2f): Int {
+ // Extract RGB components from the color
+ val red = (color shr 16 and 0xFF) / 255f
+ val green = (color shr 8 and 0xFF) / 255f
+ val blue = (color and 0xFF) / 255f
+
+ // Convert RGB to HSV
+ val hsv = rgbToHsv(red, green, blue)
+
+ // Adjust brightness (value) within bounds
+ hsv[2] = (hsv[2] + factor).coerceIn(0f, 1f)
+
+ // Convert back to RGB and return the color as an Int
+ return hsvToColor(hsv)
+}
+
+private fun rgbToHsv(r: Float, g: Float, b: Float): FloatArray {
+ val max = maxOf(r, g, b)
+ val min = minOf(r, g, b)
+ val delta = max - min
+
+ val h: Float = when {
+ delta == 0f -> 0f
+ max == r -> ((g - b) / delta + (if (g < b) 6 else 0)) % 6
+ max == g -> (b - r) / delta + 2
+ else -> (r - g) / delta + 4
+ } * 60
+
+ val s: Float = if (max == 0f) 0f else delta / max
+ val v: Float = max
+
+ return floatArrayOf(h, s, v)
+}
+
+private fun hsvToColor(hsv: FloatArray): Int {
+ val h = hsv[0]
+ val s = hsv[1]
+ val v = hsv[2]
+
+ val c = v * s
+ val x = c * (1 - ((h / 60) % 2 - 1).absoluteValue)
+ val m = v - c
+
+ val (r, g, b) = when {
+ h < 60 -> Triple(c, x, 0f)
+ h < 120 -> Triple(x, c, 0f)
+ h < 180 -> Triple(0f, c, x)
+ h < 240 -> Triple(0f, x, c)
+ h < 300 -> Triple(x, 0f, c)
+ else -> Triple(c, 0f, x)
+ }
+
+ val red = ((r + m) * 255).toInt()
+ val green = ((g + m) * 255).toInt()
+ val blue = ((b + m) * 255).toInt()
+
+ return (255 shl 24) or (red shl 16) or (green shl 8) or blue
}
/**
@@ -152,27 +192,20 @@ private fun Color.brighten(factor: Float = 0.2f): Color {
val brightenedArgb = brightenColor(argb, factor)
return Color(brightenedArgb)
}
+fun darkenColor(color: Int, factor: Float = 0.2f): Int {
+ // Extract RGB components from the color
+ val red = (color shr 16 and 0xFF) / 255f
+ val green = (color shr 8 and 0xFF) / 255f
+ val blue = (color and 0xFF) / 255f
+
+ // Convert RGB to HSV
+ val hsv = rgbToHsv(red, green, blue)
+
+ // Adjust brightness (value) within bounds
+ hsv[2] = (hsv[2] - factor).coerceIn(0f, 1f)
-private fun darkenColor(color: Int, factor: Float = 0.2f): Int {
- // Convert the color to RGB components
- val red = android.graphics.Color.red(color) / 255f
- val green = android.graphics.Color.green(color) / 255f
- val blue = android.graphics.Color.blue(color) / 255f
-
- // Convert RGB to HSL
- val hsl = FloatArray(3)
- android.graphics.Color.RGBToHSV(
- (red * 255).toInt(),
- (green * 255).toInt(),
- (blue * 255).toInt(),
- hsl,
- )
-
- // Adjust lightness (value) within bounds
- hsl[2] = (hsl[2] - factor).coerceIn(0f, 1f)
-
- // Convert back to RGB
- return android.graphics.Color.HSVToColor(hsl)
+ // Convert back to RGB and return the color as an Int
+ return hsvToColor(hsv)
}
private fun Color.darken(factor: Float = 0.2f): Color {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt
similarity index 92%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt
index 537f2f4b..57f76067 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ErrorMessage.kt
@@ -13,12 +13,11 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
@Composable
@@ -83,7 +82,7 @@ data class ActionData(
// region Preview
-@PreviewLightDark
+
@Composable
private fun PreviewErrorMessage() {
val themeColor = remember { mutableStateOf(TransportMode.Ferry().colorCode) }
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt
similarity index 93%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt
index 977756a6..b8b812b7 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCard.kt
@@ -20,6 +20,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Add
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -31,29 +33,31 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.components.SeparatorIcon
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.theme.getForegroundColor
-import xyz.ksharma.krail.design.system.toAdaptiveDecorativeIconSize
-import xyz.ksharma.krail.design.system.toAdaptiveSize
-import xyz.ksharma.krail.trip.planner.ui.R
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_a11y
+import krail.feature.trip_planner.ui.generated.resources.ic_alert
+import krail.feature.trip_planner.ui.generated.resources.ic_clock
+import krail.feature.trip_planner.ui.generated.resources.ic_walk
+import org.jetbrains.compose.resources.painterResource
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.components.SeparatorIcon
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.theme.getForegroundColor
+import xyz.ksharma.krail.taj.toAdaptiveDecorativeIconSize
+import xyz.ksharma.krail.taj.toAdaptiveSize
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.TransportModeLine
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableState
@@ -196,8 +200,6 @@ fun ExpandedJourneyCardContent(
onAlertClick: () -> Unit,
modifier: Modifier = Modifier,
) {
- val context = LocalContext.current
-
Column(modifier = modifier) {
FlowRow(
modifier = Modifier
@@ -232,12 +234,12 @@ fun ExpandedJourneyCardContent(
) {
if (totalUniqueServiceAlerts > 0) {
SmallButton(
- icon = R.drawable.ic_alert,
- text = context.resources.getQuantityString(
- R.plurals.alerts,
- totalUniqueServiceAlerts,
- totalUniqueServiceAlerts,
- ),
+ painter = painterResource(Res.drawable.ic_alert),
+ text = if (totalUniqueServiceAlerts > 1) {
+ "$totalUniqueServiceAlerts Alerts"
+ } else {
+ "$totalUniqueServiceAlerts Alert"
+ },
color = getForegroundColor(KrailTheme.colors.alert),
iconSize = iconSize,
onClick = onAlertClick,
@@ -246,7 +248,7 @@ fun ExpandedJourneyCardContent(
}
TextWithIcon(
- icon = R.drawable.ic_clock,
+ painter = painterResource(Res.drawable.ic_clock),
text = totalTravelTime,
textStyle = KrailTheme.typography.bodyLarge,
iconSize = iconSize,
@@ -366,7 +368,7 @@ fun DefaultJourneyCardContent(
}
}
- platformNumber?.let { platform -> // todo - extract
+ platformNumber?.let { platform ->
Box(
modifier = Modifier
.padding(start = 8.dp)
@@ -380,7 +382,7 @@ fun DefaultJourneyCardContent(
contentAlignment = Alignment.Center,
) {
Text(
- text = platform.toString(),
+ text = platform,
textAlign = TextAlign.Center,
style = KrailTheme.typography.labelLarge,
)
@@ -409,7 +411,7 @@ fun DefaultJourneyCardContent(
modifier = Modifier.padding(end = 10.dp),
)
TextWithIcon(
- icon = R.drawable.ic_clock,
+ painter = painterResource(Res.drawable.ic_clock),
text = totalTravelTime,
modifier = Modifier
.align(Alignment.CenterVertically)
@@ -417,7 +419,7 @@ fun DefaultJourneyCardContent(
)
totalWalkTime?.let {
TextWithIcon(
- icon = R.drawable.ic_walk,
+ painter = painterResource(Res.drawable.ic_walk),
text = totalWalkTime,
modifier = Modifier
.align(Alignment.CenterVertically)
@@ -427,7 +429,7 @@ fun DefaultJourneyCardContent(
Spacer(modifier = Modifier.weight(1f))
if (isWheelchairAccessible) {
Image(
- painter = painterResource(R.drawable.ic_a11y),
+ painter = painterResource(Res.drawable.ic_a11y),
contentDescription = null,
colorFilter = ColorFilter.tint(color = KrailTheme.colors.onSurface),
modifier = Modifier
@@ -441,7 +443,7 @@ fun DefaultJourneyCardContent(
@Composable
private fun TextWithIcon(
- icon: Int,
+ painter: Painter,
text: String,
modifier: Modifier = Modifier,
textStyle: TextStyle = KrailTheme.typography.bodyMedium,
@@ -456,7 +458,7 @@ private fun TextWithIcon(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Image(
- painter = painterResource(icon),
+ painter = painter,
contentDescription = null,
colorFilter = ColorFilter.tint(color = color.copy(alpha = contentAlpha)),
modifier = Modifier
@@ -473,7 +475,7 @@ private fun TextWithIcon(
@Composable
private fun SmallButton(
- icon: Int,
+ painter: Painter,
text: String,
modifier: Modifier = Modifier,
textStyle: TextStyle = KrailTheme.typography.bodyMedium,
@@ -503,7 +505,7 @@ private fun SmallButton(
horizontalArrangement = Arrangement.spacedBy(4.dp),
) {
Image(
- painter = painterResource(icon),
+ painter = painter,
contentDescription = null,
colorFilter = ColorFilter.tint(color = color.copy(alpha = contentAlpha)),
modifier = Modifier
@@ -530,8 +532,8 @@ internal fun List?.toColors(onSurface: Color): List = when
// region Previews
-@PreviewLightDark
-@Preview(fontScale = 2f)
+
+//@Preview(fontScale = 2f)
@Composable
private fun PreviewJourneyCard() {
KrailTheme {
@@ -556,8 +558,8 @@ private fun PreviewJourneyCard() {
}
}
-@PreviewLightDark
-@Preview(fontScale = 2f)
+
+//@Preview(fontScale = 2f)
@Composable
private fun PreviewJourneyCardCollapsed() {
KrailTheme {
@@ -596,7 +598,7 @@ private fun PreviewJourneyCardCollapsed() {
),
),
- ),
+ ),
cardState = JourneyCardState.EXPANDED,
totalWalkTime = "10 mins",
totalUniqueServiceAlerts = 1,
@@ -605,8 +607,6 @@ private fun PreviewJourneyCardCollapsed() {
}
}
-@PreviewLightDark
-@Preview(fontScale = 2f)
@Composable
private fun PreviewJourneyCardExpanded() {
KrailTheme {
@@ -671,8 +671,6 @@ private val PREVIEW_STOPS = persistentListOf(
),
)
-@Preview
-@Preview(fontScale = 2f)
@Composable
private fun PreviewJourneyCardLongData() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCardState.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCardState.kt
similarity index 100%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCardState.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/JourneyCardState.kt
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt
similarity index 93%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt
index d6708741..a9e98e6a 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/LegView.kt
@@ -28,24 +28,23 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.painterResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.toAdaptiveDecorativeIconSize
-import xyz.ksharma.krail.trip.planner.ui.R
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_a11y
+import krail.feature.trip_planner.ui.generated.resources.ic_clock
+import org.jetbrains.compose.resources.painterResource
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.toAdaptiveDecorativeIconSize
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.TransportModeLine
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableState
@@ -120,14 +119,8 @@ fun LegView(
.padding(start = 16.dp, top = 12.dp),
) {
if (stops.size > 2) {
- val context = LocalContext.current
StopsRow(
- // Need to pass count twice - https://developer.android.com/guide/topics/resources/string-resource#Plurals
- stops = context.resources.getQuantityString(
- R.plurals.stops,
- stops.size - 2,
- stops.size - 2,
- ),
+ stops = if (stops.size == 1) "${stops.size} stop" else "${stops.size} stops",
line = transportModeLine,
)
} else {
@@ -208,7 +201,7 @@ private fun RouteSummary(
if (displayDuration) {
Row(horizontalArrangement = Arrangement.End) {
Image(
- painter = painterResource(R.drawable.ic_clock),
+ painter = painterResource(Res.drawable.ic_clock),
contentDescription = null,
colorFilter = ColorFilter.tint(color = KrailTheme.colors.onSurface),
modifier = Modifier
@@ -253,7 +246,7 @@ private fun StopInfo(
)
if (isWheelchairAccessible) {
Image(
- painter = painterResource(R.drawable.ic_a11y),
+ painter = painterResource(Res.drawable.ic_a11y),
contentDescription = null,
colorFilter = ColorFilter.tint(
color = if (isProminent) {
@@ -309,8 +302,6 @@ private fun StopsRow(stops: String, line: TransportModeLine, modifier: Modifier
// region Previews
-@PreviewLightDark
-@Preview(fontScale = 2f)
@Composable
private fun PreviewLegView() {
KrailTheme {
@@ -344,8 +335,6 @@ private fun PreviewLegView() {
}
}
-@PreviewLightDark
-@Preview(fontScale = 2f)
@Composable
private fun PreviewLegViewTwoStops() {
KrailTheme {
@@ -374,7 +363,6 @@ private fun PreviewLegViewTwoStops() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewLegViewMetro() {
KrailTheme {
@@ -403,7 +391,6 @@ private fun PreviewLegViewMetro() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewLegViewFerry() {
KrailTheme {
@@ -432,7 +419,6 @@ private fun PreviewLegViewFerry() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewLegViewLightRail() {
KrailTheme {
@@ -461,7 +447,6 @@ private fun PreviewLegViewLightRail() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewStopsRow() {
KrailTheme {
@@ -475,7 +460,6 @@ private fun PreviewStopsRow() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewProminentStopInfo() {
KrailTheme {
@@ -489,8 +473,6 @@ private fun PreviewProminentStopInfo() {
}
}
-@Preview
-@Preview(fontScale = 2f)
@Composable
private fun PreviewRouteSummary() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt
similarity index 97%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt
index c2c4494c..f7cdd1be 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/OriginDestination.kt
@@ -19,8 +19,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
@Composable
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt
similarity index 91%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt
index 58afffb3..683498c4 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SavedTripCard.kt
@@ -12,6 +12,8 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Star
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -21,19 +23,17 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.semantics
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_star_filled
+import org.jetbrains.compose.resources.painterResource
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
-import xyz.ksharma.krail.design.system.R as DSR
@Composable
fun SavedTripCard(
@@ -92,7 +92,7 @@ fun SavedTripCard(
contentAlignment = Alignment.Center,
) {
Image(
- imageVector = ImageVector.vectorResource(DSR.drawable.star_filled),
+ painter = painterResource(Res.drawable.ic_star_filled),
contentDescription = "Save Trip",
colorFilter = ColorFilter.tint(
primaryTransportMode?.colorCode
@@ -105,7 +105,6 @@ fun SavedTripCard(
// region Previews
-@PreviewComponent
@Composable
private fun SavedTripCardPreview() {
KrailTheme {
@@ -127,7 +126,6 @@ private fun SavedTripCardPreview() {
}
}
-@PreviewLightDark
@Composable
private fun SavedTripCardListPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt
similarity index 78%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt
index d73f9866..da6f6441 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/SearchStopRow.kt
@@ -10,6 +10,9 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Edit
+import androidx.compose.material.icons.filled.Search
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
@@ -17,21 +20,20 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalOnContentColor
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.components.RoundIconButton
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.components.TextFieldButton
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_reverse
+import krail.feature.trip_planner.ui.generated.resources.ic_search
+import org.jetbrains.compose.resources.painterResource
+import xyz.ksharma.krail.taj.LocalOnContentColor
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.components.RoundIconButton
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.components.TextFieldButton
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.model.StopItem
-import xyz.ksharma.krail.trip.planner.ui.R as TripPlannerUiR
@Composable
fun SearchStopRow(
@@ -69,14 +71,14 @@ fun SearchStopRow(
TextFieldButton(onClick = fromButtonClick) {
Text(
text = fromStopItem?.stopName
- ?: stringResource(TripPlannerUiR.string.from_text_field_placeholder),
+ ?: "Where from",
maxLines = 1,
)
}
TextFieldButton(onClick = toButtonClick) {
Text(
text = toStopItem?.stopName
- ?: stringResource(TripPlannerUiR.string.to_text_field_placeholder),
+ ?: "Where to",
maxLines = 1,
)
}
@@ -90,7 +92,7 @@ fun SearchStopRow(
RoundIconButton(
content = {
Image(
- imageVector = ImageVector.vectorResource(TripPlannerUiR.drawable.ic_reverse),
+ painter = painterResource(Res.drawable.ic_reverse),
contentDescription = "Reverse",
colorFilter = ColorFilter.tint(LocalOnContentColor.current),
)
@@ -101,7 +103,7 @@ fun SearchStopRow(
RoundIconButton(
content = {
Image(
- imageVector = ImageVector.vectorResource(TripPlannerUiR.drawable.ic_search),
+ painter = painterResource(Res.drawable.ic_search),
contentDescription = "Search",
colorFilter = ColorFilter.tint(LocalOnContentColor.current),
)
@@ -114,7 +116,6 @@ fun SearchStopRow(
// region Previews
-@PreviewComponent
@Composable
private fun SearchStopColumnPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt
similarity index 92%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt
index 88997717..93c44b0b 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/StopSearchListItem.kt
@@ -11,13 +11,11 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.persistentSetOf
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.model.StopItem
@@ -64,7 +62,6 @@ fun StopSearchListItem(
// region Preview
-@PreviewComponent
@Composable
private fun StopSearchListItemPreview() {
KrailTheme {
@@ -81,7 +78,6 @@ private fun StopSearchListItemPreview() {
}
}
-@Preview
@Composable
private fun StopSearchListItemLongNamePreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TimelineModifiers.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TimelineModifiers.kt
similarity index 100%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TimelineModifiers.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TimelineModifiers.kt
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt
similarity index 90%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt
index 2e32e30d..a6f90458 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeBadge.kt
@@ -15,9 +15,8 @@ import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun TransportModeBadge(
@@ -48,7 +47,6 @@ fun TransportModeBadge(
// region Previews
-@PreviewComponent
@Composable
private fun TransportModeBadgeBusPreview() {
KrailTheme {
@@ -59,7 +57,6 @@ private fun TransportModeBadgeBusPreview() {
}
}
-@PreviewComponent
@Composable
private fun TransportModeBadgeTrainPreview() {
KrailTheme {
@@ -70,7 +67,6 @@ private fun TransportModeBadgeTrainPreview() {
}
}
-@PreviewComponent
@Composable
private fun TransportModeBadgeFerryPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt
similarity index 91%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt
index cf709e45..249c17a1 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeIcon.kt
@@ -17,10 +17,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun TransportModeIcon(
@@ -67,7 +66,7 @@ private fun Modifier.borderIfEnabled(enabled: Boolean): Modifier =
// region Previews
-@PreviewComponent
+
@Composable
private fun TrainPreview() {
KrailTheme {
@@ -75,7 +74,7 @@ private fun TrainPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun BusPreview() {
KrailTheme {
@@ -86,7 +85,7 @@ private fun BusPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun MetroPreview() {
KrailTheme {
@@ -97,7 +96,7 @@ private fun MetroPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun LightRailPreview() {
KrailTheme {
@@ -108,7 +107,7 @@ private fun LightRailPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun FerryPreview() {
KrailTheme {
@@ -119,7 +118,7 @@ private fun FerryPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun TrainWithBackgroundPreview() {
KrailTheme {
@@ -131,7 +130,6 @@ private fun TrainWithBackgroundPreview() {
}
}
-@PreviewComponent
@Composable
private fun BusWithBackgroundPreview() {
KrailTheme {
@@ -143,7 +141,7 @@ private fun BusWithBackgroundPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun MetroWithBackgroundPreview() {
KrailTheme {
@@ -155,7 +153,7 @@ private fun MetroWithBackgroundPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun LightRailWithBackgroundPreview() {
KrailTheme {
@@ -167,7 +165,7 @@ private fun LightRailWithBackgroundPreview() {
}
}
-@PreviewComponent
+
@Composable
private fun FerryWithBackgroundPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt
similarity index 87%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt
index 61f728cd..7cb379eb 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/TransportModeInfo.kt
@@ -6,10 +6,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun TransportModeInfo(
@@ -39,8 +38,6 @@ fun TransportModeInfo(
// region Previews
-@Preview
-@Preview(fontScale = 2.0f)
@Composable
private fun TransportModeInfoPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt
similarity index 77%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt
index a67d4224..aab41145 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/WalkingLeg.kt
@@ -10,14 +10,15 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.platform.LocalDensity
-import androidx.compose.ui.res.painterResource
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.trip.planner.ui.R
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_walk
+import org.jetbrains.compose.resources.painterResource
+import org.jetbrains.compose.ui.tooling.preview.Preview
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun WalkingLeg(
@@ -36,7 +37,7 @@ fun WalkingLeg(
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
Image(
- painter = painterResource(id = R.drawable.ic_walk),
+ painter = painterResource(Res.drawable.ic_walk),
contentDescription = null,
colorFilter = ColorFilter.tint(
color = KrailTheme.colors.onSurface.copy(alpha = contentAlpha),
@@ -47,7 +48,7 @@ fun WalkingLeg(
}
}
-@Preview(showBackground = true)
+@Preview
@Composable
private fun PreviewWalkingLeg() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/FestivalType.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/FestivalType.kt
similarity index 100%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/FestivalType.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/FestivalType.kt
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt
similarity index 94%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt
index e171c4dd..bbf13cd0 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiAnim.kt
@@ -16,10 +16,9 @@ import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.graphicsLayer
-import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.sp
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.components.loading.LoadingEmojiManager.getRandomEmoji
@Composable
@@ -70,7 +69,7 @@ fun LoadingEmojiAnim(modifier: Modifier = Modifier, emoji: String? = null) {
}
}
-@Preview
+//@Preview
@Composable
private fun Preview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt
similarity index 87%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt
index 574022f3..d27d98fd 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/components/loading/LoadingEmojiManager.kt
@@ -3,8 +3,8 @@ package xyz.ksharma.krail.trip.planner.ui.components.loading
import kotlinx.collections.immutable.persistentListOf
import kotlinx.datetime.Clock
import kotlinx.datetime.TimeZone
+import kotlinx.datetime.number
import kotlinx.datetime.todayIn
-import java.time.MonthDay
import kotlin.random.Random
object LoadingEmojiManager {
@@ -35,6 +35,13 @@ object LoadingEmojiManager {
FestivalType.CHINESE_NEW_YEAR to listOf("🧧"),
)
+ // TODO - test logic
+ data class MonthDay(val month: Int, val dayOfMonth: Int) {
+ companion object {
+ fun of(month: Int, dayOfMonth: Int) = MonthDay(month, dayOfMonth)
+ }
+ }
+
private val knownFestivalDates = mapOf(
FestivalType.CHRISTMAS to MonthDay.of(12, 25),
FestivalType.NEW_YEAR to MonthDay.of(1, 1),
@@ -48,7 +55,7 @@ object LoadingEmojiManager {
val today = Clock.System.todayIn(TimeZone.currentSystemDefault())
val festivalEmoji = knownFestivalDates.entries
- .firstOrNull { it.value.month == today.month && it.value.dayOfMonth == today.dayOfMonth }
+ .firstOrNull { it.value.month == today.month.number && it.value.dayOfMonth == today.dayOfMonth }
?.let { festivalEmojiMap[it.key]?.randomOrNull() }
if (festivalEmoji != null) return festivalEmoji
diff --git a/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/di/ViewModelModule.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/di/ViewModelModule.kt
new file mode 100644
index 00000000..40ada16f
--- /dev/null
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/di/ViewModelModule.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail.trip.planner.ui.di
+
+import org.koin.core.module.dsl.viewModelOf
+import org.koin.dsl.module
+import xyz.ksharma.krail.trip.planner.ui.savedtrips.SavedTripsViewModel
+import xyz.ksharma.krail.trip.planner.ui.searchstop.SearchStopViewModel
+import xyz.ksharma.krail.trip.planner.ui.timetable.TimeTableViewModel
+import xyz.ksharma.krail.trip.planner.ui.usualride.UsualRideViewModel
+
+val viewModelsModule = module {
+ viewModelOf(::SavedTripsViewModel)
+ viewModelOf(::SearchStopViewModel)
+ viewModelOf(::TimeTableViewModel)
+ viewModelOf(::UsualRideViewModel)
+}
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt
similarity index 69%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt
index 5de59eea..7c64272b 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/navigation/TripPlannerDestinations.kt
@@ -15,7 +15,7 @@ import xyz.ksharma.krail.trip.planner.ui.usualride.usualRideDestination
* It contains all the screens in the feature Trip Planner.
*/
fun NavGraphBuilder.tripPlannerDestinations(
- // TODO - do not wanna add NavController here, but moving all callbacks to app module is not scaleable.
+ // TODO - do not wanna add NavController here, but moving all callbacks to android-app module is not scaleable.
navController: NavHostController,
) {
navigation(startDestination = SavedTripsRoute) {
@@ -31,9 +31,20 @@ fun NavGraphBuilder.tripPlannerDestinations(
}
}
-internal enum class SearchStopFieldType(val key: String) {
- FROM(key = "FromSearchStopResult"),
- TO(key = "ToSearchStopResult"),
+@Serializable
+internal sealed class SearchStopFieldType(val key: String) {
+ data object FROM : SearchStopFieldType("FromSearchStopResult")
+ data object TO : SearchStopFieldType("ToSearchStopResult")
+
+ companion object {
+ fun fromKey(key: String): SearchStopFieldType {
+ return when (key) {
+ FROM.key -> FROM
+ TO.key -> TO
+ else -> throw IllegalArgumentException("Unknown key: $key")
+ }
+ }
+ }
}
@Serializable
@@ -51,7 +62,10 @@ internal data class TimeTableRoute(
)
@Serializable
-internal data class SearchStopRoute(val fieldType: SearchStopFieldType)
+internal data class SearchStopRoute(val fieldTypeKey: String) {
+ val fieldType: SearchStopFieldType
+ get() = SearchStopFieldType.fromKey(fieldTypeKey)
+}
@Serializable
data object UsualRideRoute
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt
similarity index 86%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt
index 5f47aaa6..36d07467 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsDestination.kt
@@ -5,13 +5,12 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
-import timber.log.Timber
+import org.koin.compose.viewmodel.koinViewModel
import xyz.ksharma.krail.trip.planner.ui.navigation.SavedTripsRoute
import xyz.ksharma.krail.trip.planner.ui.navigation.SearchStopFieldType
import xyz.ksharma.krail.trip.planner.ui.navigation.SearchStopRoute
@@ -23,7 +22,7 @@ import xyz.ksharma.krail.trip.planner.ui.state.searchstop.model.StopItem.Compani
@Suppress("LongMethod")
internal fun NavGraphBuilder.savedTripsDestination(navController: NavHostController) {
composable { backStackEntry ->
- val viewModel = hiltViewModel()
+ val viewModel: SavedTripsViewModel = koinViewModel()
val savedTripState by viewModel.uiState.collectAsStateWithLifecycle()
val fromArg: String? =
@@ -45,12 +44,12 @@ internal fun NavGraphBuilder.savedTripsDestination(navController: NavHostControl
LaunchedEffect(fromArg) {
fromArg?.let { fromStopItem = fromJsonString(it) }
- Timber.d("Change fromStopItem: $fromStopItem")
+// Timber.d("Change fromStopItem: $fromStopItem")
}
LaunchedEffect(toArg) {
toArg?.let { toStopItem = fromJsonString(it) }
- Timber.d("Change toStopItem: $toStopItem")
+// Timber.d("Change toStopItem: $toStopItem")
}
SavedTripsScreen(
@@ -58,18 +57,18 @@ internal fun NavGraphBuilder.savedTripsDestination(navController: NavHostControl
fromStopItem = fromStopItem,
toStopItem = toStopItem,
fromButtonClick = {
- Timber.d("fromButtonClick - nav: ${SearchStopRoute(fieldType = SearchStopFieldType.FROM)}")
- navController.navigate(SearchStopRoute(fieldType = SearchStopFieldType.FROM))
+ // Timber.d("fromButtonClick - nav: ${SearchStopRoute(fieldType = SearchStopFieldType.FROM)}")
+ navController.navigate(SearchStopRoute(fieldTypeKey = SearchStopFieldType.FROM.key))
},
toButtonClick = {
- Timber.d("toButtonClick - nav: ${SearchStopRoute(fieldType = SearchStopFieldType.TO)}")
+ // Timber.d("toButtonClick - nav: ${SearchStopRoute(fieldType = SearchStopFieldType.TO)}")
navController.navigate(
- route = SearchStopRoute(fieldType = SearchStopFieldType.TO),
+ route = SearchStopRoute(fieldTypeKey = SearchStopFieldType.TO.key),
navOptions = NavOptions.Builder().setLaunchSingleTop(true).build(),
)
},
onReverseButtonClick = {
- Timber.d("onReverseButtonClick:")
+ // Timber.d("onReverseButtonClick:")
val bufferStop = fromStopItem
backStackEntry.savedStateHandle[SearchStopFieldType.FROM.key] =
toStopItem?.toJsonString()
@@ -102,7 +101,7 @@ internal fun NavGraphBuilder.savedTripsDestination(navController: NavHostControl
)
} else {
// TODO - show message - to select both stops
- Timber.e("Select both stops")
+ // Timber.e("Select both stops")
}
},
onEvent = { event -> viewModel.onEvent(event) },
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt
similarity index 82%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt
index 4ced2e6d..a4c1961a 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsScreen.kt
@@ -1,8 +1,5 @@
package xyz.ksharma.krail.trip.planner.ui.savedtrips
-import androidx.activity.ComponentActivity
-import androidx.activity.SystemBarStyle
-import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
@@ -15,28 +12,24 @@ import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalThemeContentColor
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.components.TitleBar
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.trip.planner.ui.R
+import xyz.ksharma.krail.taj.LocalThemeContentColor
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.components.TitleBar
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.components.ErrorMessage
import xyz.ksharma.krail.trip.planner.ui.components.SavedTripCard
import xyz.ksharma.krail.trip.planner.ui.components.SearchStopRow
-import xyz.ksharma.krail.trip.planner.ui.components.hexToComposeColor
-import xyz.ksharma.krail.trip.planner.ui.getActivityOrNull
import xyz.ksharma.krail.trip.planner.ui.state.savedtrip.SavedTripUiEvent
import xyz.ksharma.krail.trip.planner.ui.state.savedtrip.SavedTripsState
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.model.StopItem
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_reverse
+import org.jetbrains.compose.resources.painterResource
+
@Composable
fun SavedTripsScreen(
@@ -51,8 +44,8 @@ fun SavedTripsScreen(
onEvent: (SavedTripUiEvent) -> Unit = {},
) {
val themeContentColor by LocalThemeContentColor.current
- val context = LocalContext.current
- DisposableEffect(themeContentColor) {
+ // TODO - handle colors of status bar
+/* DisposableEffect(themeContentColor) {
context.getActivityOrNull()?.let { activity ->
(activity as ComponentActivity).enableEdgeToEdge(
navigationBarStyle = SystemBarStyle.auto(
@@ -62,7 +55,7 @@ fun SavedTripsScreen(
)
}
onDispose {}
- }
+ }*/
Box(
modifier = modifier
@@ -72,7 +65,7 @@ fun SavedTripsScreen(
) {
Column {
TitleBar(title = {
- Text(text = stringResource(R.string.saved_trips_screen_title))
+ Text(text = "Saved Trips")
})
LazyColumn(
@@ -116,8 +109,7 @@ fun SavedTripsScreen(
},
primaryTransportMode = null, // TODO
modifier = Modifier
- .padding(horizontal = 16.dp)
- .animateItem(),
+ .padding(horizontal = 16.dp),
)
Spacer(modifier = Modifier.height(12.dp))
@@ -140,7 +132,6 @@ fun SavedTripsScreen(
// region Previews
-@PreviewLightDark
@Composable
private fun SavedTripsScreenPreview() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt
similarity index 51%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt
index 5e81dd15..344eba5f 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/savedtrips/SavedTripsViewModel.kt
@@ -2,48 +2,47 @@ package xyz.ksharma.krail.trip.planner.ui.savedtrips
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-import timber.log.Timber
-import xyz.ksharma.krail.di.AppDispatchers
-import xyz.ksharma.krail.di.Dispatcher
import xyz.ksharma.krail.sandook.Sandook
-import xyz.ksharma.krail.sandook.di.SandookFactory
+import xyz.ksharma.krail.sandook.SavedTrip
import xyz.ksharma.krail.trip.planner.ui.state.savedtrip.SavedTripUiEvent
import xyz.ksharma.krail.trip.planner.ui.state.savedtrip.SavedTripsState
import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
-import javax.inject.Inject
-@HiltViewModel
-class SavedTripsViewModel @Inject constructor(
- sandookFactory: SandookFactory,
- @Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
+class SavedTripsViewModel(
+ private val sandook: Sandook,
) : ViewModel() {
- private val sandook: Sandook = sandookFactory.create(SandookFactory.SandookKey.SAVED_TRIP)
-
private val _uiState: MutableStateFlow = MutableStateFlow(SavedTripsState())
val uiState: StateFlow = _uiState
private fun loadSavedTrips() {
- viewModelScope.launch(context = ioDispatcher) {
- val trips = sandook.keys().mapNotNull { key ->
- val tripString = sandook.getString(key, null)
- tripString?.let { tripJsonString ->
- Trip.fromJsonString(tripJsonString)
- }
- }.toImmutableList()
+ viewModelScope.launch(context = Dispatchers.IO) {
+ val trips = mutableSetOf()
+
+ val savedTrips = sandook.selectAllTrips()
+ println("SavedTrips: $savedTrips")
+ savedTrips.forEachIndexed { index, savedTrip ->
+ val trip = savedTrip.toTrip()
+ println("Trip: #$index $trip")
+ trips.add(savedTrip.toTrip())
+ }
+ trips.addAll(savedTrips.map { savedTrip -> savedTrip.toTrip() })
+
+ println("SavedTrips: ${trips.size} number")
trips.forEachIndexed { index, trip ->
- Timber.d("\t SavedTrip: #$index ${trip.fromStopName} -> ${trip.toStopName}")
+ println("\t SavedTrip: #$index ${trip.fromStopName} -> ${trip.toStopName}")
}
- updateUiState { copy(savedTrips = trips) }
+ updateUiState { copy(savedTrips = trips.toImmutableList()) }
}
}
@@ -55,9 +54,9 @@ class SavedTripsViewModel @Inject constructor(
}
private fun onDeleteSavedTrip(savedTrip: Trip) {
- Timber.d("onDeleteSavedTrip: $savedTrip")
- viewModelScope.launch(context = ioDispatcher) {
- sandook.remove(key = savedTrip.tripId)
+ println("onDeleteSavedTrip: $savedTrip")
+ viewModelScope.launch(context = Dispatchers.IO) {
+ sandook.deleteTrip(tripId = savedTrip.tripId)
loadSavedTrips()
}
}
@@ -66,3 +65,10 @@ class SavedTripsViewModel @Inject constructor(
_uiState.update(block)
}
}
+
+private fun SavedTrip.toTrip(): Trip = Trip(
+ fromStopId = fromStopId,
+ fromStopName = fromStopName,
+ toStopId = toStopId,
+ toStopName = toStopName,
+)
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt
similarity index 81%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt
index 774cbbed..4757f2a9 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopDestination.kt
@@ -1,25 +1,24 @@
package xyz.ksharma.krail.trip.planner.ui.searchstop
import androidx.compose.runtime.getValue
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
-import timber.log.Timber
+import org.koin.compose.viewmodel.koinViewModel
import xyz.ksharma.krail.trip.planner.ui.navigation.SearchStopRoute
fun NavGraphBuilder.searchStopDestination(navController: NavHostController) {
composable { backStackEntry ->
- val viewModel = hiltViewModel()
+ val viewModel: SearchStopViewModel = koinViewModel()
val searchStopState by viewModel.uiState.collectAsStateWithLifecycle()
val route: SearchStopRoute = backStackEntry.toRoute()
SearchStopScreen(
searchStopState = searchStopState,
onStopSelect = { stopItem ->
- Timber.d("onStopSelected: fieldTypeKey=${route.fieldType.key} and stopItem: $stopItem")
+ //Timber.d("onStopSelected: fieldTypeKey=${route.fieldType.key} and stopItem: $stopItem")
navController.previousBackStackEntry?.savedStateHandle?.set(
route.fieldType.key,
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt
similarity index 94%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt
index bffc7bbb..ca05c977 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopScreen.kt
@@ -25,22 +25,22 @@ import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
-import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableSet
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.mapLatest
-import timber.log.Timber
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.components.Divider
-import xyz.ksharma.krail.design.system.components.TextField
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import kotlinx.datetime.Clock
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.components.Divider
+import xyz.ksharma.krail.taj.components.TextField
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.components.ErrorMessage
import xyz.ksharma.krail.trip.planner.ui.components.StopSearchListItem
import xyz.ksharma.krail.trip.planner.ui.components.backgroundColorOf
@@ -50,6 +50,7 @@ import xyz.ksharma.krail.trip.planner.ui.state.searchstop.SearchStopState
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.SearchStopUiEvent
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.model.StopItem
+@OptIn(FlowPreview::class, ExperimentalCoroutinesApi::class)
@Composable
fun SearchStopScreen(
searchStopState: SearchStopState,
@@ -76,7 +77,7 @@ fun SearchStopScreen(
.debounce(250)
.filter { it.isNotBlank() }
.mapLatest { text ->
- Timber.d("Query - $text")
+ // Timber.d("Query - $text")
onEvent(SearchStopUiEvent.SearchTextChanged(text))
}.collectLatest {}
}
@@ -93,7 +94,7 @@ fun SearchStopScreen(
// track the time of the last query. If new results come in during the delay period,
// then lastQueryTime will be different, therefore, it will prevent
// "No match found" message from being displayed.
- val currentQueryTime = System.currentTimeMillis()
+ val currentQueryTime = Clock.System.now().toEpochMilliseconds()
lastQueryTime = currentQueryTime
delay(1000)
if (lastQueryTime == currentQueryTime && searchStopState.stops.isEmpty()) {
@@ -130,7 +131,7 @@ fun SearchStopScreen(
input.filter { it.isLetterOrDigit() || it.isWhitespace() }
},
) { value ->
- Timber.d("value: $value")
+ //Timber.d("value: $value")
textFieldText = value.toString()
}
@@ -188,7 +189,6 @@ fun SearchStopScreen(
// region Previews
-@Preview
@Composable
private fun PreviewSearchStopScreenLoading() {
KrailTheme {
@@ -202,7 +202,6 @@ private fun PreviewSearchStopScreenLoading() {
}
}
-@Preview
@Composable
private fun PreviewSearchStopScreenError() {
KrailTheme {
@@ -216,7 +215,6 @@ private fun PreviewSearchStopScreenError() {
}
}
-@Preview
@Composable
private fun PreviewSearchStopScreenEmpty() {
KrailTheme {
@@ -234,7 +232,6 @@ private fun PreviewSearchStopScreenEmpty() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenTrain() {
KrailTheme {
@@ -248,7 +245,6 @@ private fun PreviewSearchStopScreenTrain() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenCoach() {
KrailTheme {
@@ -262,7 +258,6 @@ private fun PreviewSearchStopScreenCoach() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenFerry() {
KrailTheme {
@@ -276,7 +271,6 @@ private fun PreviewSearchStopScreenFerry() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenMetro() {
KrailTheme {
@@ -290,7 +284,6 @@ private fun PreviewSearchStopScreenMetro() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenLightRail() {
KrailTheme {
@@ -304,7 +297,6 @@ private fun PreviewSearchStopScreenLightRail() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewSearchStopScreenBus() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt
similarity index 67%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt
index 2861edb0..e48affbc 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/SearchStopViewModel.kt
@@ -2,25 +2,18 @@ package xyz.ksharma.krail.trip.planner.ui.searchstop
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
-import timber.log.Timber
-import xyz.ksharma.krail.trip.planner.network.api.model.StopFinderResponse
-import xyz.ksharma.krail.trip.planner.network.api.repository.TripPlanningRepository
+import xyz.ksharma.krail.trip.planner.network.api.service.TripPlanningService
import xyz.ksharma.krail.trip.planner.ui.searchstop.StopResultMapper.toStopResults
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.SearchStopState
import xyz.ksharma.krail.trip.planner.ui.state.searchstop.SearchStopUiEvent
-import javax.inject.Inject
-@HiltViewModel
-class SearchStopViewModel @Inject constructor(
- private val tripPlanningRepository: TripPlanningRepository,
-) : ViewModel() {
+class SearchStopViewModel(private val tripPlanningService: TripPlanningService) : ViewModel() {
private val _uiState: MutableStateFlow = MutableStateFlow(SearchStopState())
val uiState: StateFlow = _uiState
@@ -32,17 +25,21 @@ class SearchStopViewModel @Inject constructor(
}
private fun onSearchTextChanged(query: String) {
- Timber.d("onSearchTextChanged: $query")
+ //Timber.d("onSearchTextChanged: $query")
updateUiState { displayLoading() }
viewModelScope.launch {
- tripPlanningRepository.stopFinder(stopSearchQuery = query)
- .onSuccess { response: StopFinderResponse ->
- val results = response.toStopResults()
- updateUiState { displayData(results) }
- }.onFailure {
- updateUiState { displayError() }
- }
+ runCatching {
+ val response = tripPlanningService.stopFinder(stopSearchQuery = query)
+ println("response VM: $response")
+
+ val results = response.toStopResults()
+ println("results: $results")
+
+ updateUiState { displayData(results) }
+ }.getOrElse {
+ updateUiState { displayError() }
+ }
}
}
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt
similarity index 93%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt
index a4257826..acc4aeb2 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/searchstop/StopResultMapper.kt
@@ -19,12 +19,16 @@ object StopResultMapper {
fun StopFinderResponse.toStopResults(
selectedModes: Set = TransportMode.values(),
): List {
+ println( "selectedModes: " + selectedModes)
+
return locations.orEmpty().mapNotNull { location ->
val stopName = location.disassembledName ?: return@mapNotNull null // Skip if stop name is null
val stopId = location.id ?: return@mapNotNull null // Skip if stop ID is null
val modes = location.productClasses.orEmpty()
.mapNotNull { productClass -> TransportMode.toTransportModeType(productClass) }
+ println("productClasses [${location.name}]: ${location.productClasses}")
+
// Filter based on selected mode types
if (selectedModes.isNotEmpty() && !modes.any { it in selectedModes }) {
return@mapNotNull null
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt
similarity index 92%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt
index dbefc756..9b8ed166 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableDestination.kt
@@ -1,14 +1,13 @@
package xyz.ksharma.krail.trip.planner.ui.timetable
import androidx.compose.runtime.getValue
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import androidx.navigation.toRoute
-import timber.log.Timber
+import org.koin.compose.viewmodel.koinViewModel
import xyz.ksharma.krail.trip.planner.ui.navigation.ServiceAlertRoute
import xyz.ksharma.krail.trip.planner.ui.navigation.TimeTableRoute
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableUiEvent
@@ -16,7 +15,7 @@ import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
internal fun NavGraphBuilder.timeTableDestination(navController: NavHostController) {
composable { backStackEntry ->
- val viewModel = hiltViewModel()
+ val viewModel: TimeTableViewModel = koinViewModel()
val timeTableState by viewModel.uiState.collectAsStateWithLifecycle()
val route: TimeTableRoute = backStackEntry.toRoute()
val isLoading by viewModel.isLoading.collectAsStateWithLifecycle()
@@ -33,7 +32,7 @@ internal fun NavGraphBuilder.timeTableDestination(navController: NavHostControll
onEvent = { viewModel.onEvent(it) },
onBackClick = { navController.popBackStack() },
onAlertClick = { journeyId ->
- Timber.d("journeyId: $journeyId")
+ println("journeyId: $journeyId")
viewModel.fetchAlertsForJourney(journeyId) { alerts ->
if (alerts.isNotEmpty()) {
navController.navigate(
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt
similarity index 90%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt
index fc1e723a..38b66d44 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableScreen.kt
@@ -1,8 +1,5 @@
package xyz.ksharma.krail.trip.planner.ui.timetable
-import androidx.activity.ComponentActivity
-import androidx.activity.SystemBarStyle
-import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -21,9 +18,10 @@ import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBack
+import androidx.compose.material.icons.filled.Star
+import androidx.compose.material.icons.outlined.Star
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@@ -31,27 +29,25 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.platform.LocalContext
-import androidx.compose.ui.res.stringResource
-import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.contentDescription
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.LocalThemeContentColor
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.components.TitleBar
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.theme.shouldUseDarkIcons
-import xyz.ksharma.krail.trip.planner.ui.R
+import krail.feature.trip_planner.ui.generated.resources.Res
+import krail.feature.trip_planner.ui.generated.resources.ic_reverse
+import krail.feature.trip_planner.ui.generated.resources.ic_star
+import krail.feature.trip_planner.ui.generated.resources.ic_star_filled
+import org.jetbrains.compose.resources.painterResource
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.LocalThemeContentColor
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.components.TitleBar
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.theme.shouldUseDarkIcons
import xyz.ksharma.krail.trip.planner.ui.components.ActionData
import xyz.ksharma.krail.trip.planner.ui.components.ErrorMessage
import xyz.ksharma.krail.trip.planner.ui.components.JourneyCard
@@ -59,13 +55,11 @@ import xyz.ksharma.krail.trip.planner.ui.components.JourneyCardState
import xyz.ksharma.krail.trip.planner.ui.components.OriginDestination
import xyz.ksharma.krail.trip.planner.ui.components.hexToComposeColor
import xyz.ksharma.krail.trip.planner.ui.components.loading.LoadingEmojiAnim
-import xyz.ksharma.krail.trip.planner.ui.getActivityOrNull
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.TransportModeLine
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableState
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableUiEvent
import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
-import xyz.ksharma.krail.design.system.R as DesignSystemR
@Composable
fun TimeTableScreen(
@@ -80,9 +74,8 @@ fun TimeTableScreen(
val themeContentColorHex by LocalThemeContentColor.current
val themeColor by remember { mutableStateOf(themeColorHex.hexToComposeColor()) }
val themeContentColor by remember { mutableStateOf(themeContentColorHex.hexToComposeColor()) }
- val context = LocalContext.current
val darkIcons = shouldUseDarkIcons(themeColor)
- DisposableEffect(darkIcons) {
+ /*DisposableEffect(darkIcons) {
context.getActivityOrNull()?.let { activity ->
(activity as ComponentActivity).enableEdgeToEdge(
statusBarStyle = SystemBarStyle.auto(
@@ -96,7 +89,7 @@ fun TimeTableScreen(
)
}
onDispose {}
- }
+ }*///TODO - Fix status bar colors
Column(
modifier = modifier
@@ -124,7 +117,7 @@ fun TimeTableScreen(
},
title = {
Text(
- text = stringResource(R.string.time_table_screen_title),
+ text = "TimeTable",
color = themeContentColor,
)
},
@@ -136,7 +129,7 @@ fun TimeTableScreen(
contentDescription = "Reverse Trip Search",
) {
Image(
- imageVector = ImageVector.vectorResource(R.drawable.ic_reverse),
+ painter = painterResource(Res.drawable.ic_reverse),
contentDescription = null,
colorFilter = ColorFilter.tint(themeContentColor),
modifier = Modifier.size(24.dp),
@@ -151,13 +144,11 @@ fun TimeTableScreen(
},
) {
Image(
- imageVector = ImageVector.vectorResource(
- if (timeTableState.isTripSaved) {
- DesignSystemR.drawable.star_filled
- } else {
- DesignSystemR.drawable.star_outline
- },
- ),
+ painter = if (timeTableState.isTripSaved) {
+ painterResource(Res.drawable.ic_star_filled)
+ } else {
+ painterResource(Res.drawable.ic_star)
+ },
contentDescription = null,
colorFilter = ColorFilter.tint(themeContentColor),
modifier = Modifier.size(24.dp),
@@ -336,7 +327,6 @@ fun ActionButton(
// region Preview
-@PreviewLightDark
@Composable
private fun PreviewTimeTableScreen() {
KrailTheme {
@@ -379,7 +369,6 @@ private fun PreviewTimeTableScreen() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewTimeTableScreenError() {
KrailTheme {
@@ -405,7 +394,6 @@ private fun PreviewTimeTableScreenError() {
}
}
-@PreviewLightDark
@Composable
private fun PreviewTimeTableScreenNoResults() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt
similarity index 74%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt
index ace2c8bb..8eb1679d 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/TimeTableViewModel.kt
@@ -2,10 +2,10 @@ package xyz.ksharma.krail.trip.planner.ui.timetable
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.collections.immutable.persistentListOf
import kotlinx.collections.immutable.toImmutableList
-import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.IO
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
@@ -17,45 +17,35 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
-import timber.log.Timber
import xyz.ksharma.krail.core.datetime.DateTimeHelper.calculateTimeDifferenceFromNow
import xyz.ksharma.krail.core.datetime.DateTimeHelper.toGenericFormattedTimeString
-import xyz.ksharma.krail.di.AppDispatchers
-import xyz.ksharma.krail.di.Dispatcher
import xyz.ksharma.krail.sandook.Sandook
-import xyz.ksharma.krail.sandook.di.SandookFactory
-import xyz.ksharma.krail.trip.planner.network.api.RateLimiter
import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
-import xyz.ksharma.krail.trip.planner.network.api.repository.TripPlanningRepository
+import xyz.ksharma.krail.trip.planner.network.api.ratelimit.RateLimiter
+import xyz.ksharma.krail.trip.planner.network.api.service.TripPlanningService
import xyz.ksharma.krail.trip.planner.ui.state.alerts.ServiceAlert
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableState
import xyz.ksharma.krail.trip.planner.ui.state.timetable.TimeTableUiEvent
import xyz.ksharma.krail.trip.planner.ui.state.timetable.Trip
import xyz.ksharma.krail.trip.planner.ui.timetable.business.buildJourneyList
-import xyz.ksharma.krail.trip.planner.ui.timetable.business.logForUnderstandingData
-import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
-@HiltViewModel
-class TimeTableViewModel @Inject constructor(
- private val tripRepository: TripPlanningRepository,
- sandookFactory: SandookFactory,
- @Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
+class TimeTableViewModel(
+ private val tripPlanningService: TripPlanningService,
private val rateLimiter: RateLimiter,
+ private val sandook: Sandook,
) : ViewModel() {
- private val sandook: Sandook = sandookFactory.create(SandookFactory.SandookKey.SAVED_TRIP)
-
private val _uiState: MutableStateFlow = MutableStateFlow(TimeTableState())
val uiState: StateFlow = _uiState
private val _isLoading: MutableStateFlow = MutableStateFlow(false)
val isLoading: StateFlow = _isLoading
- // Will start fetching the trip as soon as the screen is visible, which means if app goes
+ // Will start fetching the trip as soon as the screen is visible, which means if android-app goes
// to background and come back up again, the API call will be made.
// Probably good to have data up to date.
.onStart {
- Timber.d("onStart: Fetching Trip")
+ println("onStart: Fetching Trip")
fetchTrip()
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(ANR_TIMEOUT), true)
@@ -89,17 +79,17 @@ class TimeTableViewModel @Inject constructor(
}
private fun fetchTrip() {
- Timber.d("fetchTrip API Call")
- viewModelScope.launch(ioDispatcher) {
+ println("fetchTrip API Call")
+ viewModelScope.launch(Dispatchers.IO) {
// TODO - silent refresh here, UI to display loading but silent one.
rateLimiter.rateLimitFlow {
- Timber.d("rateLimitFlow block")
+ // println("rateLimitFlow block")
loadTrip()
}.catch { e ->
- Timber.e("Error while fetching trip: $e")
+ println("Error while fetching trip: $e")
}.collectLatest { result ->
result.onSuccess { response ->
- Timber.d("Success API response")
+ // println("Success API response")
updateUiState {
copy(
isLoading = false,
@@ -107,42 +97,51 @@ class TimeTableViewModel @Inject constructor(
isError = false,
)
}
- response.logForUnderstandingData()
+ //response.logForUnderstandingData()
}.onFailure {
- Timber.e("Error while fetching trip: $it")
+ // Timber.e("Error while fetching trip: $it")
updateUiState { copy(isLoading = false, isError = true) }
}
}
}
}
- private suspend fun loadTrip(): Result = withContext(ioDispatcher) {
- Timber.d("loadTrip API Call")
+ private suspend fun loadTrip(): Result = withContext(Dispatchers.IO) {
+ println("loadTrip API Call")
require(
tripInfo != null && tripInfo!!.fromStopId.isNotEmpty() && tripInfo!!.toStopId.isNotEmpty(),
) { "Trip Info is null or empty" }
- tripRepository.trip(
- originStopId = tripInfo!!.fromStopId,
- destinationStopId = tripInfo!!.toStopId,
- )
+ runCatching {
+ val tripResponse = tripPlanningService.trip(
+ originStopId = tripInfo!!.fromStopId,
+ destinationStopId = tripInfo!!.toStopId,
+ )
+ Result.success(tripResponse)
+ }.getOrElse { error ->
+ Result.failure(error)
+ }
}
private fun onSaveTripButtonClicked() {
- Timber.d("Save Trip Button Clicked")
- viewModelScope.launch(ioDispatcher) {
+ println("Save Trip Button Clicked")
+ viewModelScope.launch(Dispatchers.IO) {
tripInfo?.let { trip ->
- Timber.d("Toggle Save Trip: $trip")
- val savedTrip = sandook.getString(key = trip.tripId)
+ println("Toggle Save Trip: $trip")
+ val savedTrip = sandook.selectTripById(tripId = trip.tripId)
if (savedTrip != null) {
// Trip is already saved, so delete it
- sandook.remove(key = trip.tripId)
- Timber.d("Deleted Trip (Pref): ${Trip.fromJsonString(savedTrip)}")
+ sandook.deleteTrip(tripId = trip.tripId)
+ println("Deleted Trip (Pref): $savedTrip")
updateUiState { copy(isTripSaved = false) }
} else {
// Trip is not saved, so save it
- sandook.putString(key = trip.tripId, value = trip.toJsonString())
- Timber.d("Saved Trip (Pref): $trip")
+ sandook.insertOrReplaceTrip(
+ tripId = trip.tripId,
+ fromStopId = trip.fromStopId, fromStopName = trip.fromStopName,
+ toStopId = trip.toStopId, toStopName = trip.toStopName
+ )
+ println("Saved Trip (Pref): $trip")
updateUiState { copy(isTripSaved = true) }
}
}
@@ -150,14 +149,15 @@ class TimeTableViewModel @Inject constructor(
}
private fun onJourneyCardClicked(journeyId: String) {
- Timber.d("Journey Card Clicked(JourneyId): $journeyId")
+ println("Journey Card Clicked(JourneyId): $journeyId")
_expandedJourneyId.update { if (it == journeyId) null else journeyId }
}
private fun onLoadTimeTable(trip: Trip) {
- Timber.d("onLoadTimeTable -- Trigger fromStopItem: ${trip.fromStopId}, toStopItem: ${trip.toStopId}")
+ println("onLoadTimeTable -- Trigger fromStopItem: ${trip.fromStopId}, toStopItem: ${trip.toStopId}")
tripInfo = trip
- val savedTrip = sandook.getString(key = trip.tripId)
+ val savedTrip = sandook.selectTripById(tripId = trip.tripId)
+ println("Saved Trip[${trip.tripId}]: $savedTrip")
updateUiState {
copy(
isLoading = true,
@@ -170,7 +170,7 @@ class TimeTableViewModel @Inject constructor(
}
private fun onReverseTripButtonClicked() {
- Timber.d("Reverse Trip Button Clicked -- Trigger")
+ println("Reverse Trip Button Clicked -- Trigger")
require(tripInfo != null) { "Trip Info is null" }
val reverseTrip = Trip(
fromStopId = tripInfo!!.toStopId,
@@ -179,7 +179,7 @@ class TimeTableViewModel @Inject constructor(
toStopName = tripInfo!!.fromStopName,
)
tripInfo = reverseTrip
- val savedTrip = sandook.getString(key = reverseTrip.tripId)
+ val savedTrip = sandook.selectTripById(tripId = reverseTrip.tripId)
updateUiState {
copy(
trip = reverseTrip,
@@ -196,7 +196,7 @@ class TimeTableViewModel @Inject constructor(
* journey card should be updated.
*/
private fun updateTimeText() = viewModelScope.launch {
- val updatedJourneyList = withContext(ioDispatcher) {
+ val updatedJourneyList = withContext(Dispatchers.IO) {
_uiState.value.journeyList.map { journeyCardInfo ->
journeyCardInfo.copy(
timeText = calculateTimeDifferenceFromNow(
@@ -210,7 +210,7 @@ class TimeTableViewModel @Inject constructor(
copy(journeyList = updatedJourneyList)
}
- // Timber.d("New Time: ${uiState.value.journeyList.joinToString(", ") { it.timeText }}")
+ // println("New Time: ${uiState.value.journeyList.joinToString(", ") { it.timeText }}")
}
private inline fun updateUiState(block: TimeTableState.() -> TimeTableState) {
@@ -219,7 +219,7 @@ class TimeTableViewModel @Inject constructor(
fun fetchAlertsForJourney(journeyId: String, onResult: (Set) -> Unit) {
viewModelScope.launch {
- val alerts = withContext(ioDispatcher) {
+ val alerts = withContext(Dispatchers.IO) {
runCatching {
_uiState.value.journeyList.find { it.journeyId == journeyId }?.let { journey ->
getAlertsFromJourney(journey)
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseExt.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseExt.kt
similarity index 100%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseExt.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseExt.kt
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt
similarity index 93%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt
index 8e7099c8..afc24d11 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/TripResponseMapper.kt
@@ -2,14 +2,14 @@ package xyz.ksharma.krail.trip.planner.ui.timetable.business
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.toImmutableList
-import timber.log.Timber
-import xyz.ksharma.krail.core.datetime.DateTimeHelper.aestToHHMM
import xyz.ksharma.krail.core.datetime.DateTimeHelper.calculateTimeDifference
import xyz.ksharma.krail.core.datetime.DateTimeHelper.calculateTimeDifferenceFromNow
import xyz.ksharma.krail.core.datetime.DateTimeHelper.formatTo12HourTime
import xyz.ksharma.krail.core.datetime.DateTimeHelper.toFormattedDurationTimeString
import xyz.ksharma.krail.core.datetime.DateTimeHelper.toGenericFormattedTimeString
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.toHHMM
import xyz.ksharma.krail.core.datetime.DateTimeHelper.utcToAEST
+import xyz.ksharma.krail.core.datetime.DateTimeHelper.utcToLocalDateTimeAEST
import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
import xyz.ksharma.krail.trip.planner.ui.state.TransportModeLine
@@ -68,7 +68,7 @@ internal fun TripResponse.buildJourneyList(): ImmutableList leg.infos.orEmpty() }.toSet().size,
).also {
- Timber.d("\tJourneyId: ${it.journeyId}")
+ println("\tJourneyId: ${it.journeyId}")
}
} else {
null
@@ -113,8 +113,8 @@ fun TripResponse.Leg?.getPlatformNumber(): String? {
private fun List.logTransportModes() = forEachIndexed { index, leg ->
// log origin's disassembledName
- Timber.d("Origin #$index: ${leg.origin?.disassembledName}")
- Timber.d(
+ println("Origin #$index: ${leg.origin?.disassembledName}")
+ println(
"TransportMode #$index: ${leg.transportation?.product?.productClass}, " +
"name: ${leg.transportation?.product?.name}, " +
"stops: ${leg.stopSequence?.size}, " +
@@ -137,13 +137,13 @@ private fun List.getTransportModeLines() = mapNotNull { leg ->
private fun List.getLegsList() = mapNotNull { it.toUiModel() }.toImmutableList()
private fun String.getTimeText() = let {
- Timber.d("originTime: $it :- ${calculateTimeDifferenceFromNow(utcDateString = it)}")
+ // println("originTime: $it :- ${calculateTimeDifferenceFromNow(utcDateString = it)}")
calculateTimeDifferenceFromNow(utcDateString = it).toGenericFormattedTimeString()
}
@Suppress("ComplexCondition")
private fun TripResponse.Leg.toUiModel(): TimeTableState.JourneyCardInfo.Leg? {
- Timber.d(
+ println(
"\tFFF Leg: ${this.duration}, " +
"leg: ${this.origin?.name} TO ${this.destination?.name}" +
" - isWalk:${this.isWalkingLeg()}, " +
@@ -161,9 +161,9 @@ private fun TripResponse.Leg.toUiModel(): TimeTableState.JourneyCardInfo.Leg? {
val stops = stopSequence?.mapNotNull { it.toUiModel() }?.toImmutableList()
val alerts = infos?.mapNotNull { it.toAlert() }?.toImmutableList()
alerts?.forEach {
- Timber.d("\t Alert: ${it.heading.take(5)}, ${it.message.take(5)}, ${it.priority}")
+ //println("\t Alert: ${it.heading.take(5)}, ${it.message.take(5)}, ${it.priority}")
}
- Timber.d("Alert---")
+ // println("Alert---")
return when {
// Walking Leg - Always check before public transport leg
@@ -174,7 +174,7 @@ private fun TripResponse.Leg.toUiModel(): TimeTableState.JourneyCardInfo.Leg? {
}
else -> { // Public Transport Leg
-// Timber.d("FFF PTLeg: $displayDuration, leg: ${this.destination?.name} ")
+// println("FFF PTLeg: $displayDuration, leg: ${this.destination?.name} ")
if (transportMode != null && lineName != null && displayText != null &&
numberOfStops != null && stops != null && displayDuration != null
) {
@@ -249,19 +249,19 @@ private fun TripResponse.StopSequence.toUiModel(): TimeTableState.JourneyCardInf
}
internal fun TripResponse.logForUnderstandingData() {
- Timber.d("Journeys: ${journeys?.size}")
+ println("Journeys: ${journeys?.size}")
journeys?.mapIndexed { jindex, j ->
- Timber.d("JOURNEY #${jindex + 1}")
+ println("JOURNEY #${jindex + 1}")
j.legs?.forEachIndexed { index, leg ->
val transportationProductClass =
leg.transportation?.product?.productClass
- Timber.d(
+ println(
" LEG#${index + 1} -- Duration: ${leg.duration} -- " +
"productClass:${transportationProductClass?.toInt()}",
)
- Timber.d(
+ println(
"\t\t ORG: ${
leg.origin?.departureTimeEstimated?.utcToAEST()
?.formatTo12HourTime()
@@ -300,7 +300,7 @@ private fun List.interchangeStopsList() = this.mapNot
}
}
-private fun String.fromUTCToDisplayTimeString() = this.utcToAEST().aestToHHMM()
+private fun String.fromUTCToDisplayTimeString() = this.utcToLocalDateTimeAEST().toHHMM()
private fun TripResponse.Leg.isWalkingLeg(): Boolean =
transportation?.product?.productClass == 99L || transportation?.product?.productClass == 100L
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt
similarity index 88%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt
index be366eb2..19ce8d44 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideDestination.kt
@@ -4,15 +4,15 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
-import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavHostController
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import kotlinx.collections.immutable.toImmutableSet
-import xyz.ksharma.krail.design.system.LocalThemeColor
-import xyz.ksharma.krail.design.system.LocalThemeContentColor
-import xyz.ksharma.krail.design.system.theme.getForegroundColor
+import org.koin.compose.viewmodel.koinViewModel
+import xyz.ksharma.krail.taj.LocalThemeColor
+import xyz.ksharma.krail.taj.LocalThemeContentColor
+import xyz.ksharma.krail.taj.theme.getForegroundColor
import xyz.ksharma.krail.trip.planner.ui.components.hexToComposeColor
import xyz.ksharma.krail.trip.planner.ui.components.toHex
import xyz.ksharma.krail.trip.planner.ui.navigation.SavedTripsRoute
@@ -23,7 +23,7 @@ import xyz.ksharma.krail.trip.planner.ui.state.usualride.UsualRideEvent
internal fun NavGraphBuilder.usualRideDestination(navController: NavHostController) {
composable {
- val viewModel = hiltViewModel()
+ val viewModel:UsualRideViewModel = koinViewModel()
var themeColor by LocalThemeColor.current
var themeContentColor by LocalThemeContentColor.current
var mode: TransportMode? by remember { mutableStateOf(null) }
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt
similarity index 97%
rename from feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt
rename to feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt
index 351b91e9..08a351b2 100644
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideScreen.kt
@@ -30,14 +30,13 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.collections.immutable.ImmutableSet
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toImmutableSet
-import xyz.ksharma.krail.design.system.components.Text
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.components.Text
+import xyz.ksharma.krail.taj.theme.KrailTheme
import xyz.ksharma.krail.trip.planner.ui.components.TransportModeIcon
import xyz.ksharma.krail.trip.planner.ui.components.hexToComposeColor
import xyz.ksharma.krail.trip.planner.ui.components.transportModeBackgroundColor
@@ -184,7 +183,6 @@ private fun TransportModeRadioButton(
}
}
-@PreviewLightDark
@Composable
private fun PreviewUsualRideScreen() {
KrailTheme {
diff --git a/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt
new file mode 100644
index 00000000..a5edb147
--- /dev/null
+++ b/feature/trip-planner/ui/src/commonMain/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt
@@ -0,0 +1,30 @@
+package xyz.ksharma.krail.trip.planner.ui.usualride
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.IO
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.launch
+import xyz.ksharma.krail.sandook.Sandook
+import xyz.ksharma.krail.trip.planner.ui.state.usualride.UsualRideEvent
+import xyz.ksharma.krail.trip.planner.ui.state.usualride.UsualRideState
+
+class UsualRideViewModel(private val sandook: Sandook) : ViewModel() {
+
+ private val _uiState: MutableStateFlow = MutableStateFlow(UsualRideState())
+ val uiState: StateFlow = _uiState
+
+ fun onEvent(event: UsualRideEvent) {
+ when (event) {
+ is UsualRideEvent.TransportModeSelected -> onTransportModeSelected(event.productClass)
+ }
+ }
+
+ private fun onTransportModeSelected(productClass: Int) {
+ viewModelScope.launch(Dispatchers.IO) {
+ sandook.insertOrReplaceTheme(productClass.toLong())
+ }
+ }
+}
diff --git a/feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt b/feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt
similarity index 96%
rename from feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt
rename to feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt
index dd547f37..a926cd66 100644
--- a/feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt
+++ b/feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/components/ColorsTest.kt
@@ -2,8 +2,9 @@ package xyz.ksharma.krail.trip.planner.ui.components
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
-import org.junit.Assert.assertEquals
-import org.junit.Test
+import kotlin.test.Test
+import kotlin.test.assertEquals
+
// Define the colors
private val myWhiteLightMode = Color(0xFFFFFBFF)
@@ -35,13 +36,13 @@ fun getForegroundColor(backgroundColor: Color, isDarkMode: Boolean): Color {
return if (whiteContrast >= 4.0f) whiteColor else blackColor
}
-fun Color.toHex(): String {
+/*fun Color.toHex(): String {
val red = (this.red * 255).toInt()
val green = (this.green * 255).toInt()
val blue = (this.blue * 255).toInt()
val alpha = (this.alpha * 255).toInt()
return String.format("#%02X%02X%02X%02X", alpha, red, green, blue)
-}
+}*/
class ColorUtilsTest {
diff --git a/feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt b/feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt
similarity index 97%
rename from feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt
rename to feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt
index f558b460..407eec37 100644
--- a/feature/trip-planner/ui/src/test/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt
+++ b/feature/trip-planner/ui/src/commonTest/kotlin/xyz/ksharma/krail/trip/planner/ui/timetable/business/PlatformTextTest.kt
@@ -1,8 +1,8 @@
package xyz.ksharma.krail.trip.planner.ui.timetable.business
-import org.junit.Assert.assertEquals
-import org.junit.Test
import xyz.ksharma.krail.trip.planner.network.api.model.TripResponse
+import kotlin.test.Test
+import kotlin.test.assertEquals
class PlatformTextTest {
diff --git a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt b/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt
deleted file mode 100644
index f9c988e5..00000000
--- a/feature/trip-planner/ui/src/main/kotlin/xyz/ksharma/krail/trip/planner/ui/usualride/UsualRideViewModel.kt
+++ /dev/null
@@ -1,45 +0,0 @@
-package xyz.ksharma.krail.trip.planner.ui.usualride
-
-import androidx.lifecycle.ViewModel
-import androidx.lifecycle.viewModelScope
-import dagger.hilt.android.lifecycle.HiltViewModel
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.MutableStateFlow
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.launch
-import timber.log.Timber
-import xyz.ksharma.krail.di.AppDispatchers
-import xyz.ksharma.krail.di.Dispatcher
-import xyz.ksharma.krail.sandook.Sandook
-import xyz.ksharma.krail.sandook.di.SandookFactory
-import xyz.ksharma.krail.trip.planner.ui.state.TransportMode
-import xyz.ksharma.krail.trip.planner.ui.state.usualride.UsualRideEvent
-import xyz.ksharma.krail.trip.planner.ui.state.usualride.UsualRideState
-import javax.inject.Inject
-
-@HiltViewModel
-class UsualRideViewModel @Inject constructor(
- sandookFactory: SandookFactory,
- @Dispatcher(AppDispatchers.IO) private val ioDispatcher: CoroutineDispatcher,
-) : ViewModel() {
-
- private val sandook: Sandook = sandookFactory.create(SandookFactory.SandookKey.THEME)
-
- private val _uiState: MutableStateFlow = MutableStateFlow(UsualRideState())
- val uiState: StateFlow = _uiState
-
- fun onEvent(event: UsualRideEvent) {
- when (event) {
- is UsualRideEvent.TransportModeSelected -> onTransportModeSelected(event.productClass)
- }
- }
-
- private fun onTransportModeSelected(productClass: Int) {
- viewModelScope.launch(ioDispatcher) {
- TransportMode.toTransportModeType(productClass)?.let { mode ->
- Timber.d("onTransportModeSelected: $mode")
- sandook.putInt("selectedMode", mode.productClass)
- }
- }
- }
-}
diff --git a/gradle.properties b/gradle.properties
index 7fedda27..2d2f0c0a 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -14,3 +14,4 @@
org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
android.useAndroidX=true
org.gradle.caching=true
+kotlin.native.ignoreDisabledTargets=true
diff --git a/gradle/build-logic/convention/build.gradle.kts b/gradle/build-logic/convention/build.gradle.kts
new file mode 100644
index 00000000..24daebf4
--- /dev/null
+++ b/gradle/build-logic/convention/build.gradle.kts
@@ -0,0 +1,77 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+plugins {
+ `kotlin-dsl`
+}
+
+group = "xyz.ksharma.krail.gradle"
+
+val javaVersion = libs.versions.java.get().toInt()
+
+java {
+ sourceCompatibility = JavaVersion.values()[javaVersion - 1]
+ targetCompatibility = JavaVersion.values()[javaVersion - 1]
+}
+
+tasks.withType().configureEach {
+ compilerOptions {
+ jvmTarget.set(JvmTarget.JVM_17)
+ }
+}
+
+kotlin {
+ jvmToolchain(javaVersion)
+}
+
+dependencies {
+ compileOnly(libs.kotlin.gradlePlugin)
+ compileOnly(libs.android.gradlePlugin)
+ compileOnly(libs.compose.gradlePlugin)
+ compileOnly(libs.composeCompiler.gradlePlugin)
+}
+
+gradlePlugin {
+ plugins {
+ /**
+ * Supports building UIs for Android, Desktop, and Web using Jetpack Compose.
+ */
+ register("composeMultiplatform") {
+ id = "krail.compose.multiplatform"
+ implementationClass = "xyz.ksharma.krail.gradle.ComposeMultiplatformConventionPlugin"
+ }
+
+ /**
+ * Configures the project for Android application development.
+ */
+ register("androidApplication") {
+ id = "krail.android.application"
+ implementationClass = "xyz.ksharma.krail.gradle.AndroidApplicationConventionPlugin"
+ }
+
+ /**
+ * Configures the project for developing Android libraries.
+ */
+ register("androidLibrary") {
+ id = "krail.android.library"
+ implementationClass = "xyz.ksharma.krail.gradle.AndroidLibraryConventionPlugin"
+ }
+
+ /**
+ * Adds support for Kotlin in Android projects.
+ */
+ register("kotlinAndroid") {
+ id = "krail.kotlin.android"
+ implementationClass = "xyz.ksharma.krail.gradle.KotlinAndroidConventionPlugin"
+ }
+
+ /**
+ * Configures the project for Kotlin Multiplatform development, supporting JVM, Android, iOS,
+ * and JS targets.
+ */
+ register("kotlinMultiplatform") {
+ id = "krail.kotlin.multiplatform"
+ implementationClass = "xyz.ksharma.krail.gradle.KotlinMultiplatformConventionPlugin"
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Android.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Android.kt
new file mode 100644
index 00000000..ef7fcdf0
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Android.kt
@@ -0,0 +1,48 @@
+package xyz.ksharma.krail.gradle
+
+import com.android.build.api.dsl.CommonExtension
+import com.android.build.gradle.BaseExtension
+import org.gradle.api.JavaVersion
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.withType
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+fun Project.configureAndroid(
+) {
+ extensions.configure {
+ compileSdkVersion(AndroidVersion.COMPILE_SDK)
+
+ defaultConfig {
+ minSdk = AndroidVersion.MIN_SDK
+ targetSdk = AndroidVersion.TARGET_SDK
+ }
+
+ configureJava()
+
+ if (this is CommonExtension<*, *, *, *, *, *>) {
+ buildFeatures {
+ compose = true
+ buildConfig = true
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ }
+}
+
+object AndroidVersion {
+ // https://developer.android.com/build/releases/gradle-plugin#api-level-support
+ const val COMPILE_SDK = 34
+ const val MIN_SDK = 26 // Oreo 8.0
+ const val TARGET_SDK = 34
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidApplicationConventionPlugin.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidApplicationConventionPlugin.kt
new file mode 100644
index 00000000..5bc31781
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidApplicationConventionPlugin.kt
@@ -0,0 +1,16 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class AndroidApplicationConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.application")
+ }
+
+ configureAndroid()
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidLibraryConventionPlugin.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidLibraryConventionPlugin.kt
new file mode 100644
index 00000000..82a804d3
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/AndroidLibraryConventionPlugin.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class AndroidLibraryConventionPlugin : Plugin {
+ override fun apply(target: Project) {
+ with(target) {
+ with(pluginManager) {
+ apply("com.android.library")
+ }
+ configureAndroid()
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/ComposeMultiplatformConventionPlugin.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/ComposeMultiplatformConventionPlugin.kt
new file mode 100644
index 00000000..09683492
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/ComposeMultiplatformConventionPlugin.kt
@@ -0,0 +1,17 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+
+class ComposeMultiplatformConventionPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+
+ with(pluginManager) {
+ // Compose Multiplatform plugin - Supports building UIs for Android, Desktop, and Web
+ apply("org.jetbrains.compose")
+
+ // Enables Compose-specific features in Kotlin projects
+ apply("org.jetbrains.kotlin.plugin.compose")
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Java.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Java.kt
new file mode 100644
index 00000000..5fb27c7b
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Java.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.JavaVersion
+import org.gradle.api.Project
+import org.gradle.api.plugins.JavaPluginExtension
+import org.gradle.jvm.toolchain.JavaLanguageVersion
+import org.gradle.kotlin.dsl.configure
+
+internal fun Project.configureJava() {
+ extensions.configure {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.majorVersion))
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinAndroidConventionPlugin.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinAndroidConventionPlugin.kt
new file mode 100644
index 00000000..6ee1d27f
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinAndroidConventionPlugin.kt
@@ -0,0 +1,16 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+
+class KotlinAndroidConventionPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+
+ with(pluginManager) {
+ apply("org.jetbrains.kotlin.android") // Support Kotlin in Android projects
+ }
+ configureJava()
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinMultiplatformConventionPlugin.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinMultiplatformConventionPlugin.kt
new file mode 100644
index 00000000..78727da7
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/KotlinMultiplatformConventionPlugin.kt
@@ -0,0 +1,39 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Plugin
+import org.gradle.api.Project
+import org.gradle.kotlin.dsl.configure
+import org.gradle.kotlin.dsl.withType
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
+
+class KotlinMultiplatformConventionPlugin : Plugin {
+ override fun apply(target: Project) = with(target) {
+
+ with(pluginManager) {
+ apply("org.jetbrains.kotlin.multiplatform") // Kotlin Multiplatform plugin - JVM, Android, iOS, JS
+ }
+
+ extensions.configure {
+ applyDefaultHierarchyTemplate()
+
+ if (pluginManager.hasPlugin("com.android.library")) {
+ androidTarget()
+ }
+
+ iosArm64()
+ iosSimulatorArm64()
+
+ targets.withType().configureEach {
+ binaries.configureEach {
+ // Add linker flag for SQLite. See:
+ // https://github.com/touchlab/SQLiter/issues/77
+ // required for iOS targets
+ linkerOpts("-lsqlite3")
+ }
+ }
+
+ configureJava()
+ }
+ }
+}
diff --git a/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Libs.kt b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Libs.kt
new file mode 100644
index 00000000..750c52aa
--- /dev/null
+++ b/gradle/build-logic/convention/src/main/kotlin/xyz/ksharma/krail/gradle/Libs.kt
@@ -0,0 +1,9 @@
+package xyz.ksharma.krail.gradle
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.VersionCatalog
+import org.gradle.api.artifacts.VersionCatalogsExtension
+import org.gradle.kotlin.dsl.getByType
+
+val Project.libs
+ get(): VersionCatalog = extensions.getByType().named("libs")
diff --git a/gradle/build-logic/gradle.properties b/gradle/build-logic/gradle.properties
new file mode 100644
index 00000000..c6cd2a7e
--- /dev/null
+++ b/gradle/build-logic/gradle.properties
@@ -0,0 +1,3 @@
+org.gradle.parallel=true
+org.gradle.caching=true
+org.gradle.configureondemand=true
diff --git a/gradle/build-logic/settings.gradle.kts b/gradle/build-logic/settings.gradle.kts
new file mode 100644
index 00000000..5f522649
--- /dev/null
+++ b/gradle/build-logic/settings.gradle.kts
@@ -0,0 +1,22 @@
+dependencyResolutionManagement {
+ repositories {
+ google {
+ content {
+ includeGroupAndSubgroups("androidx")
+ includeGroupAndSubgroups("com.android")
+ includeGroupAndSubgroups("com.google")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+
+ versionCatalogs {
+ create("libs") {
+ from(files("../libs.versions.toml"))
+ }
+ }
+}
+
+rootProject.name = "build-logic"
+include(":convention")
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index e5280aae..1b154c66 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,30 +1,32 @@
[versions]
java = "17"
-agp = "8.7.2" # Android Gradle Plugin
+# AGP - Android API level mapping https://developer.android.com/build/releases/gradle-plugin#api-level-support
+agp = "8.5.2" # Android Gradle Plugin
kotlin = "2.0.21"
-core-ktx = "1.15.0"
+core-ktx = "1.13.0"
junit = "4.13.2"
androidx-test = "1.6.1"
androidx-test-ext-junit = "1.2.1"
android-lifecycle = "2.8.7"
activity-compose = "1.9.3"
-compose-bom = "2024.10.01"
-compose-navigation = "2.8.3"
-detekt = "1.23.7"
-detektCompose = "0.4.17"
-firebaseBom = "33.5.1"
-hilt = "2.52"
-hiltNavigationCompose = "1.2.0"
+kotlinInject = "0.7.2"
kotlinxCollectionsImmutable = "0.3.8"
kotlinxDatetime = "0.6.1"
-okhttpBom = "4.12.0"
+ktorClientAuth = "2.3.12"
+lifecycleViewmodelCompose = "2.8.3"
+navigationCompose = "2.8.0-alpha10"
kotlinxSerializationJson = "1.7.3"
ksp = "2.0.21-1.0.27" # ksp to kotlin version mapping https://github.com/google/ksp/releases
paparazzi = "1.3.5"
-retrofit = "2.11.0"
-retrofit2KotlinxSerializationConverter = "1.0.0"
-timber = "5.0.1"
-wire = "5.1.0"
+compose-multiplatform = "1.7.0"
+ktor = "3.0.1"
+androidx-lifecycle = "2.8.3"
+kotlinxCoroutines = "1.9.0"
+buildkonfigGradlePlugin = "0.15.2"
+kermit = "2.0.4"
+sqlDelight = "2.0.2"
+koin = "4.0.1-Beta1"
+slf4jSimple = "2.0.16"
#SDK
minSdk = "26"
@@ -32,43 +34,38 @@ compileSdk = "35"
targetSdk = "35"
[libraries]
+buildkonfig-gradle-plugin = { module = "com.codingfeline.buildkonfig:buildkonfig-gradle-plugin", version.ref = "buildkonfigGradlePlugin" }
core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core-ktx" }
activity-compose = { group = "androidx.activity", name = "activity-compose", version.ref = "activity-compose" }
-firebase-perf = { module = "com.google.firebase:firebase-perf" }
kotlinx-collections-immutable = { module = "org.jetbrains.kotlinx:kotlinx-collections-immutable", version.ref = "kotlinxCollectionsImmutable" }
kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinxDatetime" }
+ktor-client-auth = { module = "io.ktor:ktor-client-auth", version.ref = "ktorClientAuth" }
lifecycle-runtime-ktx = { group = "androidx.lifecycle", name = "lifecycle-runtime-ktx", version.ref = "android-lifecycle" }
-retrofit2-kotlinx-serialization-converter = { module = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter", version.ref = "retrofit2KotlinxSerializationConverter" }
-timber = { module = "com.jakewharton.timber:timber", version.ref = "timber" }
+navigation-compose = { module = "org.jetbrains.androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
+kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinxCoroutines" }
-#Compose
-compose-bom = { group = "androidx.compose", name = "compose-bom", version.ref = "compose-bom" }
-compose-foundation = { group = "androidx.compose.foundation", name = "foundation" }
-compose-ui = { group = "androidx.compose.ui", name = "ui" }
-compose-ui-graphics = { group = "androidx.compose.ui", name = "ui-graphics" }
-compose-ui-tooling = { group = "androidx.compose.ui", name = "ui-tooling" }
-compose-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-tooling-preview" }
-compose-navigation = { group = "androidx.navigation", name = "navigation-compose", version.ref = "compose-navigation" }
-compose-material3 = { group = "androidx.compose.material3", name = "material3", version = "1.3.1" }
+log-kermit = { module = "co.touchlab:kermit", version.ref = "kermit" }
-#Firebase
-firebase-bom = { group = "com.google.firebase", name = "firebase-bom", version.ref = "firebaseBom" }
-firebase-analytics = { module = "com.google.firebase:firebase-analytics" }
-firebase-crashlytics = { module = "com.google.firebase:firebase-crashlytics" }
+lifecycle-viewmodel-compose = { module = "org.jetbrains.androidx.lifecycle:lifecycle-viewmodel-compose", version.ref = "lifecycleViewmodelCompose" }
+androidx-lifecycle-runtime-compose = { group = "org.jetbrains.androidx.lifecycle", name = "lifecycle-runtime-compose", version.ref = "androidx-lifecycle" }
-#Hilt
-hilt-android = { group = "com.google.dagger", name = "hilt-android", version.ref = "hilt" }
-hilt-compiler = { group = "com.google.dagger", name = "hilt-compiler", version.ref = "hilt" }
-hilt-navigation-compose = { group = "androidx.hilt", name = "hilt-navigation-compose", version.ref = "hiltNavigationCompose" }
+# DI
+di-koinAndroid = {module = "io.insert-koin:koin-android", version.ref = "koin"}
+di-koinComposeViewmodel = {module = "io.insert-koin:koin-compose-viewmodel", version.ref = "koin"}
+di-koinComposeViewmodelNav = {module = "io.insert-koin:koin-compose-viewmodel-navigation", version.ref = "koin"}
#Network
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
-okhttp-logging-interceptor = { module = "com.squareup.okhttp3:logging-interceptor" }
-okhttp = { module = "com.squareup.okhttp3:okhttp" }
-okhttp-bom = { module = "com.squareup.okhttp3:okhttp-bom", version.ref = "okhttpBom" }
-retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
+ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktor" }
+ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
+ktor-client-cio = { module = "io.ktor:ktor-client-cio", version.ref = "ktor" }
+ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
+ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" }
+ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktor" }
+ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
#Test
+slf4j-simple = { module = "org.slf4j:slf4j-simple", version.ref = "slf4jSimple" }
test-composeUiTestManifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
test-composeUiTestJunit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
test-junit = { group = "junit", name = "junit", version.ref = "junit" }
@@ -79,33 +76,36 @@ test-turbine = { group = "app.cash.turbine", name = "turbine", version = "1.2.0"
test-mockitoKotlin = { group = "org.mockito.kotlin", name = "mockito-kotlin", version = "5.4.0" }
test-kotlinxCoroutineTest = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-test", version = "1.9.0" }
test-androidxCoreKtx = { group = "androidx.test", name = "core-ktx", version.ref = "androidx-test" }
-test-paparazzi = { group = "app.cash.paparazzi", name = "paparazzi-gradle-plugin", version.ref = "paparazzi" }
#BuildLogic
kotlin-gradlePlugin = { group = "org.jetbrains.kotlin", name = "kotlin-gradle-plugin", version.ref = "kotlin" }
android-gradlePlugin = { group = "com.android.tools.build", name = "gradle", version.ref = "agp" }
+compose-gradlePlugin = { module = "org.jetbrains.compose:compose-gradle-plugin", version.ref = "compose-multiplatform" }
+composeCompiler-gradlePlugin = { module = "org.jetbrains.kotlin:compose-compiler-gradle-plugin", version.ref = "kotlin" }
-#CodeStyle
-detektFormat = { group = "io.gitlab.arturbosch.detekt", name = "detekt-formatting", version.ref = "detekt" }
-detektCompose = { group = "io.nlopez.compose.rules", name = "detekt", version.ref = "detektCompose" }
+#CodeStyle Use spotless plugin for multiplatform support
+
+# Database
+db-sqlAndroidDriver = { module = "app.cash.sqldelight:android-driver", version.ref = "sqlDelight" }
+db-sqlNativeDriver = { module = "app.cash.sqldelight:native-driver", version.ref = "sqlDelight" }
+db-sqlRuntime = { module = "app.cash.sqldelight:runtime", version.ref = "sqlDelight" }
[plugins]
androidApplication = { id = "com.android.application", version.ref = "agp" }
kotlinAndroid = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
-hilt = { id = "com.google.dagger.hilt.android", version.ref = "hilt" }
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
cash-paparazzi = { id = "app.cash.paparazzi", version.ref = "paparazzi" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
-detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
+buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfigGradlePlugin" }
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
-wire = { id = "com.squareup.wire", version.ref = "wire" }
google-services = { id = "com.google.gms.google-services", version = "4.4.2" }
-firebase-crashlyticsPlugin = { id = "com.google.firebase.crashlytics", version = "3.0.2" }
-firebase-performancePlugin = { id = "com.google.firebase.firebase-perf", version = "1.4.2" }
+composeMultiplatform = { id = "org.jetbrains.compose", version.ref = "compose-multiplatform" }
+kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
+sqldelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" }
#Convention Plugins
krail-android-application = { id = "krail.android.application", version = "unspecified" }
-krail-android-hilt = { id = "krail.android.hilt", version = "unspecified" }
+krail-compose-multiplatform = { id = "krail.compose.multiplatform", version = "unspecified" }
krail-android-library = { id = "krail.android.library", version = "unspecified" }
-krail-android-library-compose = { id = "krail.android.library.compose", version = "unspecified" }
-krail-jvm-library = { id = "krail.jvm.library", version = "unspecified" }
+krail-kotlin-android = { id = "krail.kotlin.android", version = "unspecified" }
+krail-kotlin-multiplatform = { id = "krail.kotlin.multiplatform", version = "unspecified" }
diff --git a/gradlew b/gradlew
index f5feea6d..b87e4980 100755
--- a/gradlew
+++ b/gradlew
@@ -164,7 +164,7 @@ fi
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
-# * the main class name
+# * the commonMain class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
diff --git a/iosApp/Configuration/Config.xcconfig b/iosApp/Configuration/Config.xcconfig
new file mode 100644
index 00000000..c713f578
--- /dev/null
+++ b/iosApp/Configuration/Config.xcconfig
@@ -0,0 +1,3 @@
+TEAM_ID=
+BUNDLE_ID=xyz.ksharma.krail
+APP_NAME=Krail App
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..70e9f1e3
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -0,0 +1,397 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557BA273AAA24004C7B11 /* Assets.xcassets */; };
+ 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */; };
+ 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2152FB032600AC8F00CF470E /* iOSApp.swift */; };
+ 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXFileReference section */
+ 058557BA273AAA24004C7B11 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
+ 2152FB032600AC8F00CF470E /* iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iOSApp.swift; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.xcfilelist; };
+ 7555FF7B242A565900829871 /* Krail App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Krail App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
+ 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ AB3632DC29227652001CCB65 /* Config.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ B92378962B6B1156000C7307 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 058557D7273AAEEB004C7B11 /* Preview Content */ = {
+ isa = PBXGroup;
+ children = (
+ 058557D8273AAEEB004C7B11 /* Preview Assets.xcassets */,
+ );
+ path = "Preview Content";
+ sourceTree = "";
+ };
+ 42799AB246E5F90AF97AA0EF /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 7555FF72242A565900829871 = {
+ isa = PBXGroup;
+ children = (
+ AB1DB47929225F7C00F7AF9C /* Configuration */,
+ 7555FF7D242A565900829871 /* iosApp */,
+ 7555FF7C242A565900829871 /* Products */,
+ 42799AB246E5F90AF97AA0EF /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 7555FF7C242A565900829871 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 7555FF7B242A565900829871 /* Krail App.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 7555FF7D242A565900829871 /* iosApp */ = {
+ isa = PBXGroup;
+ children = (
+ 058557BA273AAA24004C7B11 /* Assets.xcassets */,
+ 7555FF82242A565900829871 /* ContentView.swift */,
+ 7555FF8C242A565B00829871 /* Info.plist */,
+ 2152FB032600AC8F00CF470E /* iOSApp.swift */,
+ 058557D7273AAEEB004C7B11 /* Preview Content */,
+ );
+ path = iosApp;
+ sourceTree = "";
+ };
+ AB1DB47929225F7C00F7AF9C /* Configuration */ = {
+ isa = PBXGroup;
+ children = (
+ AB3632DC29227652001CCB65 /* Config.xcconfig */,
+ );
+ path = Configuration;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 7555FF7A242A565900829871 /* iosApp */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
+ buildPhases = (
+ F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */,
+ 7555FF77242A565900829871 /* Sources */,
+ B92378962B6B1156000C7307 /* Frameworks */,
+ 7555FF79242A565900829871 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = iosApp;
+ packageProductDependencies = (
+ );
+ productName = iosApp;
+ productReference = 7555FF7B242A565900829871 /* Krail App.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 7555FF73242A565900829871 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = YES;
+ LastSwiftUpdateCheck = 1130;
+ LastUpgradeCheck = 1540;
+ ORGANIZATIONNAME = orgName;
+ TargetAttributes = {
+ 7555FF7A242A565900829871 = {
+ CreatedOnToolsVersion = 11.3.1;
+ };
+ };
+ };
+ buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 7555FF72242A565900829871;
+ packageReferences = (
+ );
+ productRefGroup = 7555FF7C242A565900829871 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 7555FF7A242A565900829871 /* iosApp */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 7555FF79242A565900829871 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 058557D9273AAEEB004C7B11 /* Preview Assets.xcassets in Resources */,
+ 058557BB273AAA24004C7B11 /* Assets.xcassets in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputFileListPaths = (
+ );
+ inputPaths = (
+ );
+ name = "Compile Kotlin Framework";
+ outputFileListPaths = (
+ );
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [ \"YES\" = \"$OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED\" ]; then\n echo \"Skipping Gradle build task invocation due to OVERRIDE_KOTLIN_BUILD_IDE_SUPPORTED environment variable set to \\\"YES\\\"\"\n exit 0\nfi\ncd \"$SRCROOT/..\"\n./gradlew :composeApp:embedAndSignAppleFrameworkForXcode\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 7555FF77242A565900829871 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 2152FB042600AC8F00CF470E /* iOSApp.swift in Sources */,
+ 7555FF83242A565900829871 /* ContentView.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 7555FFA3242A565B00829871 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ NEW_SETTING = "";
+ ONLY_ACTIVE_ARCH = YES;
+ "OTHER_LDFLAGS[sdk=iphone*]" = "-lsqlite3";
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ };
+ name = Debug;
+ };
+ 7555FFA4242A565B00829871 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = AB3632DC29227652001CCB65 /* Config.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
+ CLANG_CXX_LIBRARY = "libc++";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = NO;
+ GCC_C_LANGUAGE_STANDARD = gnu11;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ NEW_SETTING = "";
+ "OTHER_LDFLAGS[sdk=iphone*]" = "-lsqlite3";
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ SWIFT_OPTIMIZATION_LEVEL = "-O";
+ VALIDATE_PRODUCT = YES;
+ };
+ name = Release;
+ };
+ 7555FFA6242A565B00829871 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+ DEVELOPMENT_TEAM = "${TEAM_ID}";
+ ENABLE_PREVIEWS = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+ );
+ INFOPLIST_FILE = iosApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
+ PRODUCT_NAME = "${APP_NAME}";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Debug;
+ };
+ 7555FFA7242A565B00829871 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ CODE_SIGN_IDENTITY = "Apple Development";
+ CODE_SIGN_STYLE = Automatic;
+ DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
+ DEVELOPMENT_TEAM = "${TEAM_ID}";
+ ENABLE_PREVIEWS = YES;
+ FRAMEWORK_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n$(SRCROOT)/../composeApp/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
+ );
+ INFOPLIST_FILE = iosApp/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
+ PRODUCT_NAME = "${APP_NAME}";
+ PROVISIONING_PROFILE_SPECIFIER = "";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = "1,2";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7555FFA3242A565B00829871 /* Debug */,
+ 7555FFA4242A565B00829871 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 7555FFA6242A565B00829871 /* Debug */,
+ 7555FFA7242A565B00829871 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 7555FF73242A565900829871 /* Project object */;
+}
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 00000000..18d98100
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/parora.xcuserdatad/UserInterfaceState.xcuserstate b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/parora.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 00000000..45937bee
Binary files /dev/null and b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/parora.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/iosApp/iosApp.xcodeproj/xcuserdata/parora.xcuserdatad/xcschemes/xcschememanagement.plist b/iosApp/iosApp.xcodeproj/xcuserdata/parora.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 00000000..56b5955f
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/xcuserdata/parora.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,14 @@
+
+
+
+
+ SchemeUserState
+
+ iosApp.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+
+
diff --git a/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json b/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 00000000..ee7e3ca0
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
\ No newline at end of file
diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 00000000..8edf56e7
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,14 @@
+{
+ "images" : [
+ {
+ "filename" : "app-icon-1024.png",
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png
new file mode 100644
index 00000000..bc98427c
Binary files /dev/null and b/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png differ
diff --git a/iosApp/iosApp/Assets.xcassets/Contents.json b/iosApp/iosApp/Assets.xcassets/Contents.json
new file mode 100644
index 00000000..4aa7c535
--- /dev/null
+++ b/iosApp/iosApp/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
\ No newline at end of file
diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift
new file mode 100644
index 00000000..762bcbe2
--- /dev/null
+++ b/iosApp/iosApp/ContentView.swift
@@ -0,0 +1,18 @@
+import UIKit
+import SwiftUI
+import KrailApp
+
+struct ComposeView: UIViewControllerRepresentable {
+ func makeUIViewController(context: Context) -> UIViewController {
+ MainViewControllerKt.MainViewController()
+ }
+
+ func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
+}
+
+struct ContentView: View {
+ var body: some View {
+ ComposeView()
+ .ignoresSafeArea()
+ }
+}
diff --git a/iosApp/iosApp/Info.plist b/iosApp/iosApp/Info.plist
new file mode 100644
index 00000000..412e3781
--- /dev/null
+++ b/iosApp/iosApp/Info.plist
@@ -0,0 +1,50 @@
+
+
+
+
+ CFBundleDevelopmentRegion
+ $(DEVELOPMENT_LANGUAGE)
+ CFBundleExecutable
+ $(EXECUTABLE_NAME)
+ CFBundleIdentifier
+ $(PRODUCT_BUNDLE_IDENTIFIER)
+ CFBundleInfoDictionaryVersion
+ 6.0
+ CFBundleName
+ $(PRODUCT_NAME)
+ CFBundlePackageType
+ $(PRODUCT_BUNDLE_PACKAGE_TYPE)
+ CFBundleShortVersionString
+ 1.0
+ CFBundleVersion
+ 1
+ LSRequiresIPhoneOS
+
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSceneManifest
+
+ UIApplicationSupportsMultipleScenes
+
+
+ UILaunchScreen
+
+ UIRequiredDeviceCapabilities
+
+ armv7
+
+ UISupportedInterfaceOrientations
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+ UISupportedInterfaceOrientations~ipad
+
+ UIInterfaceOrientationPortrait
+ UIInterfaceOrientationPortraitUpsideDown
+ UIInterfaceOrientationLandscapeLeft
+ UIInterfaceOrientationLandscapeRight
+
+
+
diff --git a/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json b/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
new file mode 100644
index 00000000..4aa7c535
--- /dev/null
+++ b/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
\ No newline at end of file
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
new file mode 100644
index 00000000..8fa5091d
--- /dev/null
+++ b/iosApp/iosApp/iOSApp.swift
@@ -0,0 +1,13 @@
+import SwiftUI
+
+@main
+struct iOSApp: App {
+ init() {
+ }
+
+ var body: some Scene {
+ WindowGroup {
+ ContentView()
+ }
+ }
+}
diff --git a/sandook/api/build.gradle.kts b/sandook/api/build.gradle.kts
deleted file mode 100644
index 749b3eb4..00000000
--- a/sandook/api/build.gradle.kts
+++ /dev/null
@@ -1,3 +0,0 @@
-plugins {
- alias(libs.plugins.krail.jvm.library)
-}
diff --git a/sandook/build.gradle.kts b/sandook/build.gradle.kts
new file mode 100644
index 00000000..fb611254
--- /dev/null
+++ b/sandook/build.gradle.kts
@@ -0,0 +1,62 @@
+plugins {
+ alias(libs.plugins.krail.android.library)
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.kotlin.serialization)
+ alias(libs.plugins.ksp)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.sqldelight)
+}
+
+android {
+ namespace = "xyz.ksharma.krail.sandook"
+}
+
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+
+ iosArm64()
+ iosSimulatorArm64()
+
+ java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.majorVersion))
+ }
+ }
+
+ sourceSets {
+ androidMain {
+ dependencies {
+ implementation(libs.db.sqlAndroidDriver)
+ implementation(libs.di.koinAndroid)
+ }
+ }
+
+ commonMain {
+ dependencies {
+ implementation(libs.kotlinx.serialization.json)
+
+ implementation(compose.runtime)
+ implementation(libs.log.kermit)
+ implementation(libs.kotlinx.datetime)
+ implementation(libs.db.sqlRuntime)
+ api(libs.di.koinComposeViewmodel)
+ }
+ }
+
+ iosMain.dependencies {
+ implementation(libs.ktor.client.darwin)
+ api(libs.db.sqlNativeDriver)
+ }
+ }
+}
+
+sqldelight {
+ databases {
+ create("KrailSandook") {
+ packageName.set("xyz.ksharma.krail.sandook")
+ }
+ }
+}
diff --git a/sandook/real/build.gradle.kts b/sandook/real/build.gradle.kts
deleted file mode 100644
index 2166ad06..00000000
--- a/sandook/real/build.gradle.kts
+++ /dev/null
@@ -1,14 +0,0 @@
-plugins {
- alias(libs.plugins.krail.android.library)
- alias(libs.plugins.krail.android.hilt)
-}
-
-android {
- namespace = "xyz.ksharma.krail.sandook.real"
-}
-
-dependencies {
- implementation(projects.sandook.api)
-
- implementation(libs.kotlinx.serialization.json)
-}
diff --git a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt b/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt
deleted file mode 100644
index a0400356..00000000
--- a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt
+++ /dev/null
@@ -1,57 +0,0 @@
-package xyz.ksharma.krail.sandook
-
-import android.content.SharedPreferences
-import javax.inject.Inject
-
-internal class RealSandook @Inject constructor(private val sharedPreferences: SharedPreferences) : Sandook {
-
- override fun keys(): Set = sharedPreferences.all.keys
-
- override fun putString(key: String, value: String) {
- sharedPreferences.edit().putString(key, value).apply()
- }
-
- override fun getString(key: String, defaultValue: String?): String? {
- return sharedPreferences.getString(key, defaultValue)
- }
-
- override fun putInt(key: String, value: Int) {
- sharedPreferences.edit().putInt(key, value).apply()
- }
-
- override fun getInt(key: String, defaultValue: Int): Int {
- return sharedPreferences.getInt(key, defaultValue)
- }
-
- override fun putBoolean(key: String, value: Boolean) {
- sharedPreferences.edit().putBoolean(key, value).apply()
- }
-
- override fun getBoolean(key: String, defaultValue: Boolean): Boolean {
- return sharedPreferences.getBoolean(key, defaultValue)
- }
-
- override fun putFloat(key: String, value: Float) {
- sharedPreferences.edit().putFloat(key, value).apply()
- }
-
- override fun getFloat(key: String, defaultValue: Float): Float {
- return sharedPreferences.getFloat(key, defaultValue)
- }
-
- override fun putLong(key: String, value: Long) {
- sharedPreferences.edit().putLong(key, value).apply()
- }
-
- override fun getLong(key: String, defaultValue: Long): Long {
- return sharedPreferences.getLong(key, defaultValue)
- }
-
- override fun remove(key: String) {
- sharedPreferences.edit().remove(key).apply()
- }
-
- override fun clear() {
- sharedPreferences.edit().clear().apply()
- }
-}
diff --git a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/Sandook.kt b/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/Sandook.kt
deleted file mode 100644
index 719435a3..00000000
--- a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/Sandook.kt
+++ /dev/null
@@ -1,22 +0,0 @@
-package xyz.ksharma.krail.sandook
-
-interface Sandook {
-
- fun clear()
- fun remove(key: String)
- fun getLong(key: String, defaultValue: Long = 0L): Long
- fun putLong(key: String, value: Long)
- fun getFloat(key: String, defaultValue: Float = 0f): Float
- fun putFloat(key: String, value: Float)
- fun getBoolean(key: String, defaultValue: Boolean = false): Boolean
- fun putBoolean(key: String, value: Boolean)
- fun getInt(key: String, defaultValue: Int = 0): Int
- fun putInt(key: String, value: Int)
- fun getString(key: String, defaultValue: String? = null): String?
- fun putString(key: String, value: String)
-
- /**
- * Returns a set of all keys in the Sandook.
- */
- fun keys(): Set
-}
diff --git a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookFactory.kt b/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookFactory.kt
deleted file mode 100644
index 329d03a8..00000000
--- a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookFactory.kt
+++ /dev/null
@@ -1,23 +0,0 @@
-package xyz.ksharma.krail.sandook.di
-
-import android.content.Context
-import dagger.hilt.android.qualifiers.ApplicationContext
-import xyz.ksharma.krail.sandook.RealSandook
-import xyz.ksharma.krail.sandook.Sandook
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class SandookFactory @Inject constructor(
- @ApplicationContext private val context: Context,
-) {
- fun create(sandookKey: SandookKey): Sandook {
- val sharedPreferences = context.getSharedPreferences(sandookKey.fileName, Context.MODE_PRIVATE)
- return RealSandook(sharedPreferences)
- }
-
- enum class SandookKey(val fileName: String) {
- SAVED_TRIP("saved_trip"),
- THEME("theme"),
- }
-}
diff --git a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt b/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt
deleted file mode 100644
index 2d76da29..00000000
--- a/sandook/real/src/main/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package xyz.ksharma.krail.sandook.di
-
-import dagger.Binds
-import dagger.Module
-import dagger.hilt.InstallIn
-import dagger.hilt.components.SingletonComponent
-import xyz.ksharma.krail.sandook.RealSandook
-import xyz.ksharma.krail.sandook.Sandook
-import javax.inject.Singleton
-
-@Module
-@InstallIn(SingletonComponent::class)
-abstract class SandookModule {
-
- @Binds
- @Singleton
- internal abstract fun bindSandook(impl: RealSandook): Sandook
-}
diff --git a/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/AndroidSandookDriverFactory.kt b/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/AndroidSandookDriverFactory.kt
new file mode 100644
index 00000000..04d9f39d
--- /dev/null
+++ b/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/AndroidSandookDriverFactory.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail.sandook
+
+import android.content.Context
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.android.AndroidSqliteDriver
+
+class AndroidSandookDriverFactory(private val context: Context) : SandookDriverFactory {
+ override fun createDriver(): SqlDriver {
+ return AndroidSqliteDriver(
+ schema = KrailSandook.Schema,
+ context = context,
+ name = "krailSandook.db"
+ )
+ }
+}
diff --git a/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/di/AndroidSandookModule.kt b/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/di/AndroidSandookModule.kt
new file mode 100644
index 00000000..f8b027e5
--- /dev/null
+++ b/sandook/src/androidMain/kotlin/xyz/ksharma/krail/sandook/di/AndroidSandookModule.kt
@@ -0,0 +1,21 @@
+package xyz.ksharma.krail.sandook.di
+
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.module.dsl.bind
+import org.koin.core.module.dsl.singleOf
+import org.koin.dsl.module
+import xyz.ksharma.krail.sandook.AndroidSandookDriverFactory
+import xyz.ksharma.krail.sandook.RealSandook
+import xyz.ksharma.krail.sandook.SandookDriverFactory
+
+actual val sqlDriverModule = module {
+ singleOf(::AndroidSandookDriverFactory) { bind() }
+
+ single {
+ RealSandook(
+ factory = AndroidSandookDriverFactory(
+ context = androidContext()
+ )
+ )
+ }
+}
diff --git a/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt
new file mode 100644
index 00000000..de19e997
--- /dev/null
+++ b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/RealSandook.kt
@@ -0,0 +1,56 @@
+package xyz.ksharma.krail.sandook
+
+internal class RealSandook(factory: SandookDriverFactory) : Sandook {
+
+ private val sandook = KrailSandook(factory.createDriver())
+ private val query = sandook.krailSandookQueries
+
+ // region Theme
+ override fun insertOrReplaceTheme(productClass: Long) {
+ query.insertOrReplaceProductClass(productClass)
+ }
+
+ override fun getProductClass(): Long? {
+ return query.selectProductClass().executeAsOneOrNull()
+ }
+
+ override fun clearTheme() {
+ query.clearTheme()
+ }
+
+ // endregion
+
+ // region SavedTrip
+ override fun insertOrReplaceTrip(
+ tripId: String,
+ fromStopId: String,
+ fromStopName: String,
+ toStopId: String,
+ toStopName: String,
+ ) {
+ query.insertOrReplaceTrip(
+ tripId,
+ fromStopId,
+ fromStopName,
+ toStopId,
+ toStopName,
+ )
+ }
+
+ override fun deleteTrip(tripId: String) {
+ query.deleteTrip(tripId)
+ }
+
+ override fun selectAllTrips(): List {
+ return query.selectAllTrips().executeAsList()
+ }
+
+ override fun selectTripById(tripId: String): SavedTrip? {
+ return query.selectTripById(tripId).executeAsOneOrNull()
+ }
+
+ override fun clearSavedTrips() {
+ query.clearSavedTrips()
+ }
+ // endregion
+}
diff --git a/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/Sandook.kt b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/Sandook.kt
new file mode 100644
index 00000000..047718e4
--- /dev/null
+++ b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/Sandook.kt
@@ -0,0 +1,24 @@
+package xyz.ksharma.krail.sandook
+
+interface Sandook {
+
+ // region Theme
+ fun insertOrReplaceTheme(productClass: Long)
+ fun getProductClass(): Long?
+ fun clearTheme()
+ // endregion
+
+ // region SavedTrip
+ fun insertOrReplaceTrip(
+ tripId: String,
+ fromStopId: String,
+ fromStopName: String,
+ toStopId: String,
+ toStopName: String
+ )
+ fun deleteTrip(tripId: String)
+ fun selectAllTrips(): List
+ fun selectTripById(tripId: String): SavedTrip?
+ fun clearSavedTrips()
+ // endregion
+}
diff --git a/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/SandookFactory.kt b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/SandookFactory.kt
new file mode 100644
index 00000000..678a5186
--- /dev/null
+++ b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/SandookFactory.kt
@@ -0,0 +1,7 @@
+package xyz.ksharma.krail.sandook
+
+import app.cash.sqldelight.db.SqlDriver
+
+interface SandookDriverFactory {
+ fun createDriver(): SqlDriver
+}
diff --git a/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt
new file mode 100644
index 00000000..6ad33284
--- /dev/null
+++ b/sandook/src/commonMain/kotlin/xyz/ksharma/krail/sandook/di/SandookModule.kt
@@ -0,0 +1,15 @@
+package xyz.ksharma.krail.sandook.di
+
+import org.koin.core.module.Module
+import org.koin.core.module.dsl.bind
+import org.koin.core.module.dsl.singleOf
+import org.koin.dsl.module
+import xyz.ksharma.krail.sandook.RealSandook
+import xyz.ksharma.krail.sandook.Sandook
+
+val sandookModule = module {
+ singleOf(::RealSandook) { bind() }
+ includes(sqlDriverModule)
+}
+
+expect val sqlDriverModule: Module
diff --git a/sandook/src/commonMain/sqldelight/xyz/ksharma/krail/sandook/KrailSandook.sq b/sandook/src/commonMain/sqldelight/xyz/ksharma/krail/sandook/KrailSandook.sq
new file mode 100644
index 00000000..183515fe
--- /dev/null
+++ b/sandook/src/commonMain/sqldelight/xyz/ksharma/krail/sandook/KrailSandook.sq
@@ -0,0 +1,42 @@
+-- Theme Table --
+CREATE TABLE Theme (
+ productClass INTEGER NOT NULL
+);
+
+insertOrReplaceProductClass:
+INSERT OR REPLACE INTO Theme(productClass)
+VALUES (?);
+
+selectProductClass:
+SELECT productClass FROM Theme LIMIT 1;
+
+clearTheme:
+DELETE FROM Theme;
+
+-- Saved Trip Table --
+CREATE TABLE SavedTrip (
+ tripId TEXT PRIMARY KEY,
+ fromStopId TEXT NOT NULL,
+ fromStopName TEXT NOT NULL,
+ toStopId TEXT NOT NULL,
+ toStopName TEXT NOT NULL,
+ timestamp TEXT DEFAULT (datetime('now'))
+);
+
+insertOrReplaceTrip:
+INSERT OR REPLACE INTO SavedTrip(tripId, fromStopId, fromStopName, toStopId, toStopName, timestamp)
+VALUES (?, ?, ?, ?, ?, datetime('now'));
+
+deleteTrip:
+DELETE FROM SavedTrip WHERE tripId = ?;
+
+selectAllTrips:
+SELECT * FROM SavedTrip
+ORDER BY timestamp DESC;
+
+selectTripById:
+SELECT * FROM SavedTrip
+WHERE tripId = ?;
+
+clearSavedTrips:
+DELETE FROM SavedTrip;
diff --git a/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/IosSandookDriverFactory.kt b/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/IosSandookDriverFactory.kt
new file mode 100644
index 00000000..e9d0d03d
--- /dev/null
+++ b/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/IosSandookDriverFactory.kt
@@ -0,0 +1,10 @@
+package xyz.ksharma.krail.sandook
+
+import app.cash.sqldelight.db.SqlDriver
+import app.cash.sqldelight.driver.native.NativeSqliteDriver
+
+class IosSandookDriverFactory : SandookDriverFactory {
+ override fun createDriver(): SqlDriver {
+ return NativeSqliteDriver(KrailSandook.Schema, name = "krailSandook.db")
+ }
+}
diff --git a/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/di/IosSandookModule.kt b/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/di/IosSandookModule.kt
new file mode 100644
index 00000000..79d3fec7
--- /dev/null
+++ b/sandook/src/iosMain/kotlin/xyz/ksharma/krail/sandook/di/IosSandookModule.kt
@@ -0,0 +1,16 @@
+package xyz.ksharma.krail.sandook.di
+
+import org.koin.core.module.dsl.bind
+import org.koin.core.module.dsl.singleOf
+import org.koin.dsl.module
+import xyz.ksharma.krail.sandook.IosSandookDriverFactory
+import xyz.ksharma.krail.sandook.RealSandook
+import xyz.ksharma.krail.sandook.SandookDriverFactory
+
+actual val sqlDriverModule = module {
+ singleOf(::IosSandookDriverFactory) { bind() }
+
+ single {
+ RealSandook(factory = IosSandookDriverFactory())
+ }
+}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index eb44a49d..66f91389 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,33 +1,40 @@
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
-
- includeBuild("build-logic")
+ includeBuild("gradle/build-logic")
repositories {
- google()
+ google {
+ mavenContent {
+ includeGroupAndSubgroups("androidx")
+ includeGroupAndSubgroups("com.android")
+ includeGroupAndSubgroups("com.google")
+ }
+ }
mavenCentral()
gradlePluginPortal()
}
}
+
dependencyResolutionManagement {
- repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
- google()
+ google {
+ mavenContent {
+ includeGroupAndSubgroups("androidx")
+ includeGroupAndSubgroups("com.android")
+ includeGroupAndSubgroups("com.google")
+ }
+ }
mavenCentral()
}
}
rootProject.name = "Krail"
-include(":app")
-include(":core:coroutines-ext")
+//include(":android-app")
+include(":composeApp")
+include(":taj") // Design System
include(":core:date-time")
-include(":core:di")
-include(":core:design-system")
-include(":core:network")
-include(":feature:trip-planner:network:api")
-include(":feature:trip-planner:network:real")
-include(":feature:trip-planner:state")
include(":feature:trip-planner:ui")
-include(":sandook:api")
-include(":sandook:real")
+include(":feature:trip-planner:state")
+include(":feature:trip-planner:network")
+include(":sandook")
diff --git a/taj/build.gradle.kts b/taj/build.gradle.kts
new file mode 100644
index 00000000..422d673f
--- /dev/null
+++ b/taj/build.gradle.kts
@@ -0,0 +1,37 @@
+plugins {
+ alias(libs.plugins.krail.kotlin.multiplatform)
+ alias(libs.plugins.krail.compose.multiplatform)
+ alias(libs.plugins.compose.compiler)
+ alias(libs.plugins.krail.android.library)
+}
+
+android {
+ namespace = "xyz.ksharma.krail.taj"
+}
+
+kotlin {
+ applyDefaultHierarchyTemplate()
+
+ androidTarget()
+
+ iosArm64()
+ iosSimulatorArm64()
+
+ java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(JavaVersion.VERSION_17.majorVersion))
+ }
+ }
+
+ sourceSets {
+ commonMain {
+ dependencies {
+ implementation(compose.foundation)
+ implementation(compose.animation)
+ implementation(compose.ui)
+ implementation(compose.material3)
+ implementation(compose.runtime)
+ }
+ }
+ }
+}
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/CompositionLocals.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/CompositionLocals.kt
similarity index 94%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/CompositionLocals.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/CompositionLocals.kt
index ccf29ae5..1be538b5 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/CompositionLocals.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/CompositionLocals.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system
+package xyz.ksharma.krail.taj
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.mutableStateOf
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/DpExt.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/DpExt.kt
similarity index 95%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/DpExt.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/DpExt.kt
index f699e24e..475dce61 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/DpExt.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/DpExt.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system
+package xyz.ksharma.krail.taj
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Divider.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Divider.kt
similarity index 89%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Divider.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Divider.kt
index b4204686..d1ab971e 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Divider.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Divider.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -12,10 +12,9 @@ import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentColor
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.LocalContentColor
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun Divider(
@@ -49,7 +48,6 @@ enum class DividerType {
VERTICAL,
}
-@PreviewLightDark
@Composable
private fun DividerPreview() {
KrailTheme {
@@ -65,7 +63,6 @@ private fun DividerPreview() {
}
}
-@PreviewLightDark
@Composable
private fun DividerVerticalPreview() {
KrailTheme {
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/RoundIconButton.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/RoundIconButton.kt
similarity index 65%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/RoundIconButton.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/RoundIconButton.kt
index 678fb409..b9545cef 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/RoundIconButton.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/RoundIconButton.kt
@@ -1,6 +1,5 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
-import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
@@ -12,16 +11,11 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.ColorFilter
-import androidx.compose.ui.graphics.vector.ImageVector
-import androidx.compose.ui.res.vectorResource
import androidx.compose.ui.semantics.Role
-import xyz.ksharma.krail.design.system.LocalContentColor
-import xyz.ksharma.krail.design.system.LocalOnContentColor
-import xyz.ksharma.krail.design.system.R
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.tokens.ButtonTokens.RoundButtonSize
+import xyz.ksharma.krail.taj.LocalContentColor
+import xyz.ksharma.krail.taj.LocalOnContentColor
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.tokens.ButtonTokens.RoundButtonSize
/**
* A round icon button with customizable content and colors.
@@ -62,18 +56,4 @@ fun RoundIconButton(
// region Previews
-@PreviewComponent
-@Composable
-private fun RoundIconButtonPreview() {
- KrailTheme {
- RoundIconButton(onClick = {}) {
- Image(
- imageVector = ImageVector.vectorResource(R.drawable.star_outline),
- contentDescription = null,
- colorFilter = ColorFilter.tint(LocalOnContentColor.current),
- )
- }
- }
-}
-
// endregion
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/SeparatorIcon.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/SeparatorIcon.kt
similarity index 80%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/SeparatorIcon.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/SeparatorIcon.kt
index 22eef7d9..c3037446 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/SeparatorIcon.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/SeparatorIcon.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
@@ -10,9 +10,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.toAdaptiveSize
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.toAdaptiveSize
@Composable
fun SeparatorIcon(modifier: Modifier = Modifier, color: Color = KrailTheme.colors.onSurface) {
@@ -27,7 +26,6 @@ fun SeparatorIcon(modifier: Modifier = Modifier, color: Color = KrailTheme.color
// region Previews
-@PreviewComponent
@Composable
private fun SeparatorIconPreview() {
KrailTheme {
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Text.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Text.kt
similarity index 89%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Text.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Text.kt
index e76467d7..1709f38f 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/Text.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/Text.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Column
@@ -13,11 +13,10 @@ import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.LocalTextColor
-import xyz.ksharma.krail.design.system.LocalTextStyle
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.LocalTextColor
+import xyz.ksharma.krail.taj.LocalTextStyle
+import xyz.ksharma.krail.taj.theme.KrailTheme
@Composable
fun Text(
@@ -79,7 +78,6 @@ fun Text(
// region Previews
-@PreviewComponent
@Composable
private fun TextPreview() {
KrailTheme {
@@ -92,7 +90,6 @@ private fun TextPreview() {
}
}
-@PreviewComponent
@Composable
private fun TextWithColorPreview() {
KrailTheme {
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextField.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextField.kt
similarity index 90%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextField.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextField.kt
index 4b36d631..0b533aff 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextField.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextField.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
import androidx.compose.foundation.background
import androidx.compose.foundation.interaction.MutableInteractionSource
@@ -30,16 +30,15 @@ import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.intl.LocaleList
-import androidx.compose.ui.tooling.preview.PreviewLightDark
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.LocalTextColor
-import xyz.ksharma.krail.design.system.LocalTextStyle
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens.PlaceholderOpacity
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens.TextFieldHeight
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens.TextSelectionBackgroundOpacity
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.LocalTextColor
+import xyz.ksharma.krail.taj.LocalTextStyle
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens.PlaceholderOpacity
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens.TextFieldHeight
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens.TextSelectionBackgroundOpacity
/**
* Important documentation links:
@@ -147,7 +146,7 @@ private fun TextFieldPlaceholder(placeholder: String? = null) {
// region Previews
-@PreviewLightDark
+
@Composable
private fun TextFieldEnabledPreview() {
KrailTheme {
@@ -155,7 +154,6 @@ private fun TextFieldEnabledPreview() {
}
}
-@PreviewLightDark
@Composable
private fun TextFieldEnabledPlaceholderPreview() {
KrailTheme {
@@ -163,7 +161,6 @@ private fun TextFieldEnabledPlaceholderPreview() {
}
}
-@PreviewLightDark
@Composable
private fun TextFieldDisabledPreview() {
KrailTheme {
@@ -171,7 +168,6 @@ private fun TextFieldDisabledPreview() {
}
}
-@PreviewLightDark
@Composable
private fun TextFieldDisabledPlaceholderPreview() {
KrailTheme {
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextFieldButton.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextFieldButton.kt
similarity index 73%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextFieldButton.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextFieldButton.kt
index bffec20c..26a9105d 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/components/TextFieldButton.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TextFieldButton.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.components
+package xyz.ksharma.krail.taj.components
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
@@ -14,13 +14,12 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.dp
-import xyz.ksharma.krail.design.system.LocalContentAlpha
-import xyz.ksharma.krail.design.system.LocalTextColor
-import xyz.ksharma.krail.design.system.LocalTextStyle
-import xyz.ksharma.krail.design.system.preview.PreviewComponent
-import xyz.ksharma.krail.design.system.theme.KrailTheme
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens
-import xyz.ksharma.krail.design.system.tokens.TextFieldTokens.TextFieldHeight
+import xyz.ksharma.krail.taj.LocalContentAlpha
+import xyz.ksharma.krail.taj.LocalTextColor
+import xyz.ksharma.krail.taj.LocalTextStyle
+import xyz.ksharma.krail.taj.theme.KrailTheme
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens
+import xyz.ksharma.krail.taj.tokens.TextFieldTokens.TextFieldHeight
/**
* A button that looks like a text field.
@@ -59,17 +58,3 @@ fun TextFieldButton(
}
}
}
-
-// region Previews
-
-@PreviewComponent
-@Composable
-private fun TextFieldButtonPreview() {
- KrailTheme {
- TextFieldButton(onClick = {}) {
- Text(text = "Search")
- }
- }
-}
-
-// endregion
diff --git a/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TitleBar.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TitleBar.kt
new file mode 100644
index 00000000..c0ad1772
--- /dev/null
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/components/TitleBar.kt
@@ -0,0 +1,64 @@
+package xyz.ksharma.krail.taj.components
+
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.heightIn
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.statusBarsPadding
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
+import xyz.ksharma.krail.taj.LocalContentColor
+import xyz.ksharma.krail.taj.LocalTextColor
+import xyz.ksharma.krail.taj.LocalTextStyle
+import xyz.ksharma.krail.taj.theme.KrailTheme
+
+@Composable
+fun TitleBar(
+ title: @Composable () -> Unit,
+ modifier: Modifier = Modifier,
+ navAction: @Composable (() -> Unit)? = null,
+ actions: @Composable (() -> Unit)? = null,
+) {
+ Row(
+ modifier = modifier
+ .statusBarsPadding()
+ .fillMaxWidth()
+ .heightIn(min = 56.dp)
+ .padding(end = 16.dp, start = 8.dp)
+ .padding(vertical = 4.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ navAction?.let {
+ navAction()
+ }
+ Row(
+ modifier = Modifier
+ .weight(1f)
+ .padding(start = 10.dp),
+ ) {
+ CompositionLocalProvider(
+ LocalTextColor provides KrailTheme.colors.onSurface,
+ LocalTextStyle provides KrailTheme.typography.headlineMedium,
+ ) {
+ title()
+ }
+ }
+ actions?.let {
+ Row(
+ modifier = Modifier.padding(start = 16.dp),
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ ) {
+ CompositionLocalProvider(
+ LocalContentColor provides KrailTheme.colors.onSurface,
+ ) {
+ actions()
+ }
+ }
+ }
+ }
+}
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/A11yColors.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/A11yColors.kt
similarity index 95%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/A11yColors.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/A11yColors.kt
index 3d61e68c..7383239f 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/A11yColors.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/A11yColors.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.theme
+package xyz.ksharma.krail.taj.theme
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.luminance
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Color.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Color.kt
similarity index 98%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Color.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Color.kt
index 6e344775..b0114d34 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Color.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Color.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.theme
+package xyz.ksharma.krail.taj.theme
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/KrailTypography.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/KrailTypography.kt
similarity index 99%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/KrailTypography.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/KrailTypography.kt
index 4b70f5dd..2d6c462a 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/KrailTypography.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/KrailTypography.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.theme
+package xyz.ksharma.krail.taj.theme
import androidx.compose.runtime.Immutable
import androidx.compose.runtime.staticCompositionLocalOf
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Theme.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Theme.kt
similarity index 94%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Theme.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Theme.kt
index 1845d6f3..28f50b46 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/theme/Theme.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/theme/Theme.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.theme
+package xyz.ksharma.krail.taj.theme
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.runtime.Composable
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/ButtonTokens.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/ButtonTokens.kt
similarity index 68%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/ButtonTokens.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/ButtonTokens.kt
index b28eeaf5..a88a62e8 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/ButtonTokens.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/ButtonTokens.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.tokens
+package xyz.ksharma.krail.taj.tokens
import androidx.compose.ui.unit.dp
diff --git a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/TextFieldTokens.kt b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/TextFieldTokens.kt
similarity index 83%
rename from core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/TextFieldTokens.kt
rename to taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/TextFieldTokens.kt
index 35f1e697..66e2e13c 100644
--- a/core/design-system/src/main/kotlin/xyz/ksharma/krail/design/system/tokens/TextFieldTokens.kt
+++ b/taj/src/commonMain/kotlin/xyz/ksharma/krail/taj/tokens/TextFieldTokens.kt
@@ -1,4 +1,4 @@
-package xyz.ksharma.krail.design.system.tokens
+package xyz.ksharma.krail.taj.tokens
import androidx.compose.ui.unit.dp