diff --git a/.fleet/receipt.json b/.fleet/receipt.json
new file mode 100644
index 0000000..11a2883
--- /dev/null
+++ b/.fleet/receipt.json
@@ -0,0 +1,19 @@
+// Project generated by Kotlin Multiplatform Wizard
+{
+ "spec": {
+ "template_id": "kmt",
+ "targets": {
+ "android": {
+ "ui": [
+ "compose"
+ ]
+ },
+ "ios": {
+ "ui": [
+ "compose"
+ ]
+ }
+ }
+ },
+ "timestamp": "2024-04-15T08:24:49.936562548Z"
+}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 98816d3..33e4c75 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,17 @@
*.iml
.gradle
-/local.properties
-/.idea
+**/build/
+xcuserdata
+!src/**/build/
+local.properties
+.idea
.DS_Store
-build/
-/captures
+captures
.externalNativeBuild
.cxx
-iosApp/iosApp.xcworkspace/*
-iosApp/iosApp.xcodeproj/*
-!iosApp/iosApp.xcodeproj/project.pbxproj
+*.xcodeproj/*
+!*.xcodeproj/project.pbxproj
+!*.xcodeproj/xcshareddata/
+!*.xcodeproj/project.xcworkspace/
+!*.xcworkspace/contents.xcworkspacedata
+**/xcshareddata/WorkspaceSettings.xcsettings
diff --git a/README.md b/README.md
index 158cc2d..1ba257b 100644
--- a/README.md
+++ b/README.md
@@ -1,25 +1,14 @@
-# DecomposeNavigation
-Compose Multiplatform Bottom Navigation with Decompose
-libraries
-#Decompose
-What is Decompose?¶
-Decompose is a Kotlin Multiplatform library for breaking down your code into lifecycle-aware business logic components (aka BLoC), with routing functionality and pluggable UI (Jetpack Compose, Android Views, SwiftUI, JS React, etc.).
-https://arkivanov.github.io/Decompose/getting-started/quick-start/
-https://github.com/arkivanov/Decompose
-Also includes Depedency injection with Koin and examples of how to access Device Specific APIs
+This is a Kotlin Multiplatform project targeting Android, iOS.
-
+* `/composeApp` is for code that will be shared across your Compose Multiplatform applications.
+ It contains several subfolders:
+ - `commonMain` is for code that’s common for all targets.
+ - Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name.
+ For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app,
+ `iosMain` would be the right folder for such calls.
+* `/iosApp` contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform,
+ you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project.
+
+Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html)…
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index 10ab54a..52cf9fa 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -1,23 +1,8 @@
-buildscript {
- dependencies {
- classpath(deps.jetbrains.kotlinx.binaryCompatibilityValidator)
- classpath(deps.parcelizeDarwin.gradlePlug)
- classpath(deps.kotlin.kotlinGradlePlug)
- classpath("com.android.tools.build:gradle:8.1.1")
- //classpath(deps.plugins.spotless)
- // classpath(deps.plugins.ktlint)
- //classpath(deps.plugins.detekt)
- }
-}
-
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
- kotlin("multiplatform").apply(false)
- id("com.android.application").apply(false)
- id("com.android.library").apply(false)
- id("org.jetbrains.compose").apply(false)
-
-}
-
-
+ alias(libs.plugins.androidApplication) apply false
+ alias(libs.plugins.androidLibrary) apply false
+ alias(libs.plugins.jetbrainsCompose) apply false
+ alias(libs.plugins.kotlinMultiplatform) apply false
+}
\ No newline at end of file
diff --git a/composeApp/build.gradle.kts b/composeApp/build.gradle.kts
new file mode 100644
index 0000000..9b78622
--- /dev/null
+++ b/composeApp/build.gradle.kts
@@ -0,0 +1,180 @@
+plugins {
+ alias(libs.plugins.kotlinMultiplatform)
+ alias(libs.plugins.androidApplication)
+ alias(libs.plugins.jetbrainsCompose)
+ id("com.arkivanov.parcelize.darwin") version "0.2.3"
+ id("kotlin-parcelize")
+ id("app.cash.sqldelight") version "2.0.0"
+ kotlin("plugin.serialization") version "1.9.21"
+}
+
+kotlin {
+ androidTarget {
+ compilations.all {
+ kotlinOptions {
+ jvmTarget = "17"
+ }
+ }
+ }
+
+ listOf(
+ iosX64(),
+ iosArm64(),
+ iosSimulatorArm64()
+ ).forEach { iosTarget ->
+ iosTarget.binaries.framework {
+ baseName = "ComposeApp"
+ isStatic = true
+ export(libs.decompose)
+
+ export(libs.essenty.lifecycle)
+
+ // Optional, only if you need state preservation on Darwin (Apple) targets
+ export(libs.essenty.stateKeeper)
+
+ // Optional, only if you need state preservation on Darwin (Apple) targets
+ export(libs.parcelizeDarwin.runtime)
+
+ }
+ }
+
+ sourceSets {
+
+ androidMain.dependencies {
+ implementation(libs.compose.ui.tooling.preview)
+ implementation(libs.androidx.activity.compose)
+ implementation(libs.androidx.appcompat.appcompat)
+
+ // Ktor
+ implementation(libs.ktor.clientAndroid)
+
+ // SqlDelight
+ implementation(libs.sqlDelight.androidDriver)
+
+ // Koin
+ implementation(libs.koin.android)
+
+ implementation("com.google.android.gms:play-services-auth:21.0.0")
+
+ implementation("com.google.android.gms:play-services-auth-api-phone:18.0.2")
+
+ implementation("androidx.biometric:biometric:1.2.0-alpha05")
+ //Firebase
+ implementation ("com.google.firebase:firebase-bom:32.1.1")
+ implementation (libs.analytics.firebase)
+ implementation (libs.crashlytics.firebase)
+ implementation("com.googlecode.libphonenumber:libphonenumber:8.2.0")
+ // This dependency is downloaded from the Google’s Maven repository.
+ // So, make sure you also include that repository in your project's build.gradle file.
+ implementation("com.google.android.play:app-update:2.1.0")
+
+ // For Kotlin users also import the Kotlin extensions library for Play In-App Update:
+ implementation("com.google.android.play:app-update-ktx:2.1.0")
+
+ api ("com.github.atwa:filepicker:1.0.7")
+
+ }
+ commonMain.dependencies {
+ implementation(compose.runtime)
+ implementation(compose.foundation)
+ implementation(compose.material)
+ implementation(compose.ui)
+ implementation(compose.components.resources)
+ implementation(compose.components.uiToolingPreview)
+ implementation(compose.material3)
+ @OptIn(org.jetbrains.compose.ExperimentalComposeLibrary::class)
+ implementation(compose.materialIconsExtended)
+
+ implementation(libs.decompose)
+ implementation(libs.decompose.jetbrains)
+ api(libs.essenty.lifecycle)
+ api(libs.essenty.stateKeeper)
+
+ api(libs.ktor.clientCore)
+ api(libs.ktor.serializationKotlinxJson)
+ api(libs.ktor.clientContentNegotiation)
+ api(libs.ktor.clientLogging)
+
+ // Logback for ktor logging
+ implementation(libs.logbackClassic)
+
+ //sqldelight
+ api(libs.sqlDelight.coroutinesExtensions)
+ api(libs.sqlDelight.primitiveAdapters)
+
+ //Koin
+ api(libs.koin.core)
+ api(libs.koin.test)
+
+// // KotlinX Serialization Json
+ implementation(libs.jetbrains.kotlinx.kotlinxSerializationJson)
+//
+// // Coroutines
+ implementation(libs.jetbrains.kotlinx.kotlinxCoroutinesCore)
+//
+// // MVIKotlin
+ api(libs.mvikotlin)
+ api(libs.mviKotlin.mvikotlinMain)
+ api(libs.mviKotlin.mvikotlinExtensionsCoroutines)
+// // settings
+ implementation(libs.russhwolf.settings.core)
+ implementation(libs.russhwolf.settings.serialization)
+ //insets
+ implementation("com.moriatsushi.insetsx:insetsx:0.1.0-alpha10")
+
+ }
+
+ iosMain.dependencies {
+ //ios dependencies
+ // Ktor
+ implementation(libs.ktor.clientDarwin)
+
+ // SqlDelight
+ implementation(libs.sqlDelight.nativeDriver)
+
+ api(libs.decompose)
+
+ api(libs.essenty.lifecycle)
+ //Modified
+ api(libs.parcelizeDarwin.runtime)
+
+
+
+ }
+ }
+}
+
+android {
+ namespace = "org.example.project"
+ compileSdk = libs.versions.android.compileSdk.get().toInt()
+
+ sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
+ sourceSets["main"].res.srcDirs("src/androidMain/res")
+ sourceSets["main"].resources.srcDirs("src/commonMain/resources")
+
+ defaultConfig {
+ applicationId = "org.example.project"
+ minSdk = libs.versions.android.minSdk.get().toInt()
+ targetSdk = libs.versions.android.targetSdk.get().toInt()
+ versionCode = 1
+ versionName = "1.0"
+ }
+ packaging {
+ resources {
+ excludes += "/META-INF/{AL2.0,LGPL2.1}"
+ }
+ }
+ buildTypes {
+ getByName("release") {
+ isMinifyEnabled = false
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+ dependencies {
+ debugImplementation(libs.compose.ui.tooling)
+ }
+}
+
diff --git a/composeApp/src/androidMain/AndroidManifest.xml b/composeApp/src/androidMain/AndroidManifest.xml
new file mode 100644
index 0000000..6b0f60b
--- /dev/null
+++ b/composeApp/src/androidMain/AndroidManifest.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composeApp/src/androidMain/kotlin/Platform.android.kt b/composeApp/src/androidMain/kotlin/Platform.android.kt
new file mode 100644
index 0000000..9428cd8
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/Platform.android.kt
@@ -0,0 +1,13 @@
+import android.os.Build
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import rootBottomStack.RootBottomComponent
+
+class AndroidPlatform : Platform {
+ override val name: String = "Android ${Build.VERSION.SDK_INT}"
+}
+
+@Composable
+fun MainView(component: RootBottomComponent, modifier: Modifier = Modifier) = App(component, modifier)
+
+actual fun getPlatform(): Platform = AndroidPlatform()
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/PlatformSpecific.android.kt b/composeApp/src/androidMain/kotlin/PlatformSpecific.android.kt
new file mode 100644
index 0000000..ef1ee35
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/PlatformSpecific.android.kt
@@ -0,0 +1,193 @@
+import androidx.compose.ui.graphics.ImageBitmap
+
+import android.Manifest
+import android.app.Activity
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.net.Uri
+import android.os.Build
+import android.provider.DocumentsContract
+import android.provider.OpenableColumns
+import androidx.activity.result.contract.ActivityResultContracts
+import androidx.annotation.RequiresApi
+import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.ui.graphics.asImageBitmap
+import androidx.core.app.ActivityCompat
+import androidx.core.content.ContextCompat
+import com.atwa.filepicker.core.FilePicker
+import java.io.File
+import java.io.IOException
+
+actual open class PlatformSpecific(private val context: Context) : AppCompatActivity() {
+ private val PICK_FILE_REQUEST_CODE = 123
+ private val currentActivity: AppCompatActivity = (context as AppCompatActivity)
+ private val filePicker = FilePicker.getInstance(currentActivity)
+ private val PICK_IMAGE_REQUEST_CODE = 123
+ private val CAMERA_PERMISSION_REQUEST_CODE = 123
+ val filePickerLauncher =
+ currentActivity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
+ handleFileSelectionResult(result.resultCode, result.data?.data)
+ }
+
+ //Todo api modifications
+ //Modified to support android version below and above 13
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
+ actual fun loadFiles(callback: (ImageBitmap?) -> Unit) {
+ if (ContextCompat.checkSelfPermission(
+ currentActivity,
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
+ Manifest.permission.READ_EXTERNAL_STORAGE
+ } else {
+ Manifest.permission.READ_MEDIA_IMAGES
+ }
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ loadDeviceFiles(callback)
+ } else {
+ ActivityCompat.requestPermissions(
+ currentActivity,
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
+ arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE)
+ } else {
+ arrayOf(Manifest.permission.READ_MEDIA_IMAGES)
+ },
+ PICK_FILE_REQUEST_CODE
+ )
+ }
+ }
+
+ actual fun loadImages(callback: (ImageBitmap?) -> Unit) {
+ if (ContextCompat.checkSelfPermission(
+ currentActivity,
+ Manifest.permission.CAMERA
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ // Permission is already granted, proceed with capturing the image
+ captureImage(callback)
+ } else {
+ // Request camera permission
+ ActivityCompat.requestPermissions(
+ currentActivity,
+ arrayOf(Manifest.permission.CAMERA),
+ CAMERA_PERMISSION_REQUEST_CODE
+ )
+ }
+ }
+
+ fun openImagePicker() {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
+ intent.addCategory(Intent.CATEGORY_OPENABLE)
+ intent.type = "image/*" // Set the MIME type to allow only image files
+
+ currentActivity.startActivityForResult(intent, PICK_IMAGE_REQUEST_CODE)
+ }
+
+ @Deprecated("Deprecated in Java")
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+
+ if (requestCode == PICK_IMAGE_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
+ // Handle the selected image URI
+ val selectedImageUri: Uri? = data?.data
+ selectedImageUri?.let { uri ->
+ // Convert URI to Bitmap
+ val bitmap: Bitmap? = uriToBitmap(uri)
+
+ if (bitmap != null) {
+ // Do something with the bitmap
+
+ }
+ }
+ }
+ }
+
+ private fun uriToBitmap(uri: Uri): Bitmap? {
+ return try {
+ val inputStream = currentActivity.contentResolver.openInputStream(uri)
+ BitmapFactory.decodeStream(inputStream)
+ } catch (e: IOException) {
+ e.printStackTrace()
+ null
+ }
+ }
+
+ private fun captureImage(callback: (ImageBitmap?) -> Unit) {
+ filePicker.captureCameraImage { meta ->
+ val name: String? = meta?.name
+ val sizeKb: Int? = meta?.sizeKb
+ val file: File? = meta?.file
+ val bitmap: Bitmap? = meta?.bitmap
+ val bitmapimage: ImageBitmap? = meta?.bitmap?.asImageBitmap()
+
+ println("Picked Image:::$bitmap")
+
+ // Invoke the callback with the captured image details
+ callback(bitmapimage)
+ }
+ }
+
+ private fun loadDeviceFiles(callback: (ImageBitmap?) -> Unit) {
+ filePicker.pickImage() { meta ->
+ val name: String? = meta?.name
+ val sizeKb: Int? = meta?.sizeKb
+ val file: File? = meta?.file
+ val bitmapimage: ImageBitmap? = meta?.bitmap?.asImageBitmap()
+ callback(bitmapimage)
+ }
+ }
+
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ fun openFile(pickerInitialUri: Uri) {
+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
+ addCategory(Intent.CATEGORY_OPENABLE)
+ type = "application/pdf"
+ putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
+ }
+
+ filePickerLauncher.launch(intent)
+ }
+
+ private fun pickPdf() {
+ filePicker.pickPdf() { meta ->
+ val name: String? = meta?.name
+ val sizeKb: Int? = meta?.sizeKb
+ val file: File? = meta?.file
+ println("Loaded File name:::::" + name)
+ }
+ }
+
+ private fun getFileName(uri: Uri): String {
+ contentResolver.query(uri, null, null, null, null)?.use { cursor ->
+ val nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
+ cursor.moveToFirst()
+ return cursor.getString(nameIndex)
+ }
+ return ""
+ }
+
+ private fun handleFileSelectionResult(resultCode: Int, selectedFileUri: Uri?) {
+ if (resultCode == Activity.RESULT_OK) {
+ selectedFileUri?.let { uri ->
+ // Get the file name from the URI
+ val fileName = getFileName(uri)
+
+ // Print or use the file name as needed
+ println("Selected file name: $fileName")
+ }
+ } else {
+ println("Error opening or user canceled")
+ }
+ }
+
+ actual fun launchDialer(phoneNumber: String) {
+ val intent = Intent(Intent.ACTION_DIAL, Uri.parse("tel:$phoneNumber"))
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ context.startActivity(intent)
+
+ }
+
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/kotlin/org/example/project/MainActivity.kt b/composeApp/src/androidMain/kotlin/org/example/project/MainActivity.kt
new file mode 100644
index 0000000..1be7840
--- /dev/null
+++ b/composeApp/src/androidMain/kotlin/org/example/project/MainActivity.kt
@@ -0,0 +1,52 @@
+package org.example.project
+
+import MainView
+import PlatformSpecific
+import android.os.Bundle
+import androidx.activity.compose.setContent
+import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.tooling.preview.Preview
+import com.arkivanov.decompose.defaultComponentContext
+import di.initKoin
+import org.koin.android.ext.koin.androidContext
+import org.koin.core.context.stopKoin
+import org.koin.core.error.KoinAppAlreadyStartedException
+import rootBottomStack.DefaultRootBottomComponent
+
+class MainActivity : AppCompatActivity() {
+ private var platform: PlatformSpecific? = null
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ platform =PlatformSpecific(this)
+ val root = DefaultRootBottomComponent(
+ componentContext = defaultComponentContext(),
+ )
+ try {
+ val koinApplication = initKoin(
+ // add to build configuration, false in prod
+ enableNetworkLogs = true,
+ platform = platform
+ )
+ println("Koin app Started::;::::")
+ koinApplication.androidContext(applicationContext)
+ } catch (e: KoinAppAlreadyStartedException) {
+ println("Koin app Failed::;::::")
+ e.printStackTrace()
+ }
+ setContent {
+ MainView(root)
+ }
+ }
+
+ override fun onDestroy() {
+ stopKoin()
+ super.onDestroy()
+ }
+}
+
+@Preview
+@Composable
+fun AppAndroidPreview() {
+ // App()
+}
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml b/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/composeApp/src/androidMain/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..eca70cf
--- /dev/null
+++ b/composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..a571e60
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 0000000..61da551
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c41dd28
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 0000000..db5080a
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..6dba46d
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..da31a87
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..15ac681
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..b216f2d
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 0000000..f25a419
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 0000000..e96783c
Binary files /dev/null and b/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/composeApp/src/androidMain/res/values/strings.xml b/composeApp/src/androidMain/res/values/strings.xml
new file mode 100644
index 0000000..d8c6aef
--- /dev/null
+++ b/composeApp/src/androidMain/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ DecomposeApp
+
\ No newline at end of file
diff --git a/composeApp/src/androidMain/res/values/styles.xml b/composeApp/src/androidMain/res/values/styles.xml
new file mode 100644
index 0000000..c1f9831
--- /dev/null
+++ b/composeApp/src/androidMain/res/values/styles.xml
@@ -0,0 +1,6 @@
+
+
+
+
\ No newline at end of file
diff --git a/composeApp/src/commonMain/composeResources/drawable/CoffeeCup.png b/composeApp/src/commonMain/composeResources/drawable/CoffeeCup.png
new file mode 100644
index 0000000..4a8d285
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/CoffeeCup.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/camera.png b/composeApp/src/commonMain/composeResources/drawable/camera.png
new file mode 100644
index 0000000..ba6e143
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/camera.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml b/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml
new file mode 100644
index 0000000..d7bf795
--- /dev/null
+++ b/composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
diff --git a/composeApp/src/commonMain/composeResources/drawable/framea.png b/composeApp/src/commonMain/composeResources/drawable/framea.png
new file mode 100644
index 0000000..a534293
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/framea.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/frameb.png b/composeApp/src/commonMain/composeResources/drawable/frameb.png
new file mode 100644
index 0000000..58e6ceb
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/frameb.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/id-card.png b/composeApp/src/commonMain/composeResources/drawable/id-card.png
new file mode 100644
index 0000000..eeac703
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/id-card.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/id.png b/composeApp/src/commonMain/composeResources/drawable/id.png
new file mode 100644
index 0000000..6931491
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/id.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/imagee.png b/composeApp/src/commonMain/composeResources/drawable/imagee.png
new file mode 100644
index 0000000..6b2e8c4
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/imagee.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/img.png b/composeApp/src/commonMain/composeResources/drawable/img.png
new file mode 100644
index 0000000..519993e
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/img.png differ
diff --git a/composeApp/src/commonMain/composeResources/drawable/photos.png b/composeApp/src/commonMain/composeResources/drawable/photos.png
new file mode 100644
index 0000000..2bd0017
Binary files /dev/null and b/composeApp/src/commonMain/composeResources/drawable/photos.png differ
diff --git a/composeApp/src/commonMain/kotlin/App.kt b/composeApp/src/commonMain/kotlin/App.kt
new file mode 100644
index 0000000..e1e0e2f
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/App.kt
@@ -0,0 +1,30 @@
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.*
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import org.jetbrains.compose.ui.tooling.preview.Preview
+import rootBottomStack.RootBottomComponent
+import rootBottomStack.RootBottomScreen
+import theme.ComposeExperimentalTheme
+
+@Composable
+@Preview
+fun App(component: RootBottomComponent, modifier: Modifier = Modifier) {
+ ComposeExperimentalTheme(content = {
+ Scaffold() { paddingFromPrent ->
+ Column(
+ Modifier
+ .padding(paddingFromPrent)
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally
+ ) {
+
+ RootBottomScreen(component, modifier)
+
+ }
+ }
+ })
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/Greeting.kt b/composeApp/src/commonMain/kotlin/Greeting.kt
new file mode 100644
index 0000000..887d835
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/Greeting.kt
@@ -0,0 +1,7 @@
+class Greeting {
+ private val platform = getPlatform()
+
+ fun greet(): String {
+ return "Hello, ${platform.name}!"
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/Platform.kt b/composeApp/src/commonMain/kotlin/Platform.kt
new file mode 100644
index 0000000..87ca3ff
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/Platform.kt
@@ -0,0 +1,5 @@
+interface Platform {
+ val name: String
+}
+
+expect fun getPlatform(): Platform
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/PlatformSpecific.kt b/composeApp/src/commonMain/kotlin/PlatformSpecific.kt
new file mode 100644
index 0000000..4f940dd
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/PlatformSpecific.kt
@@ -0,0 +1,8 @@
+import androidx.compose.ui.graphics.ImageBitmap
+
+expect open class PlatformSpecific{
+ fun loadFiles(callback: (ImageBitmap?) -> Unit)
+ fun loadImages(callback: (ImageBitmap?) -> Unit)
+ fun launchDialer(phoneNumber: String)
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/about/AboutComponent.kt b/composeApp/src/commonMain/kotlin/about/AboutComponent.kt
new file mode 100644
index 0000000..6884d58
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/about/AboutComponent.kt
@@ -0,0 +1,11 @@
+package about
+
+import PlatformSpecific
+
+
+interface AboutComponent {
+ val loadFiles: PlatformSpecific
+
+ fun onUpdateGreetingText()
+ fun onBackClicked()
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/about/AboutContent.kt b/composeApp/src/commonMain/kotlin/about/AboutContent.kt
new file mode 100644
index 0000000..f47ae88
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/about/AboutContent.kt
@@ -0,0 +1,303 @@
+package about
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.wrapContentHeight
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.PathEffect
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import decomposeapp.composeapp.generated.resources.Res
+import decomposeapp.composeapp.generated.resources.camera
+import decomposeapp.composeapp.generated.resources.id_card
+import org.jetbrains.compose.resources.ExperimentalResourceApi
+import org.jetbrains.compose.resources.painterResource
+
+@OptIn(ExperimentalResourceApi::class, ExperimentalMaterial3Api::class)
+@Composable
+fun MessageContent(
+ component: AboutComponent,
+ modifier: Modifier = Modifier,
+) {
+ val mutableBitmapState: MutableState = mutableStateOf(null)
+ val mutableFrontIdBitmapState: MutableState = mutableStateOf(null)
+ val mutableBackIdBitmapState: MutableState = mutableStateOf(null)
+ val stroke = Stroke(
+ width = 2f,
+ pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 10f), 0f)
+ )
+ val color = MaterialTheme.colorScheme.onBackground
+ Scaffold(
+ modifier = Modifier.fillMaxSize(),
+ topBar = {
+ TopAppBar(title = { Text(text = "About",
+ fontSize = 15.sp) })
+ }
+ ) { innerPadding ->
+ LazyColumn(modifier = Modifier.padding(start = 16.dp, end = 16.dp)) {
+ item {
+ Spacer(modifier = Modifier.padding(innerPadding))
+ }
+ item {
+ Text(
+ text = "Upload these documents",
+ fontSize = 12.sp,
+ style = MaterialTheme.typography.titleLarge,
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ .wrapContentHeight()
+ .clickable {
+ component.loadFiles.loadImages { image ->
+ println("Loaded camera image + " + image)
+ mutableBitmapState.value = image
+ }
+ }
+ .drawBehind {
+ drawRoundRect(color = color, style = stroke)
+ }
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth(0.5f)
+ .padding(start = 5.dp)
+ ) {
+ Text(
+ text = "Take Passport Photo",
+ fontSize = 10.sp,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "Please take a photo for verification",
+ fontSize = 10.sp,
+ style = MaterialTheme.typography.bodySmall
+ )
+ }
+ if (mutableBitmapState.value == null) {
+ Image(
+ painter = painterResource(Res.drawable.camera),
+ contentDescription = "Take photo",
+ contentScale = ContentScale.FillBounds,
+ modifier = Modifier
+ .size(60.dp)
+ .padding(end = 10.dp)
+ .clickable {
+ component.loadFiles.loadImages { image ->
+ println("Loaded camera image + " + image)
+ mutableBitmapState.value = image
+ }
+ }
+ )
+ } else {
+ mutableBitmapState.value?.let { image ->
+ Image(
+ bitmap = image,
+ contentDescription = null,
+ modifier = Modifier
+ .size(150.dp)
+ .padding(1.dp),
+ alignment = Alignment.CenterEnd
+ )
+ }
+ }
+ }
+ }
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ .wrapContentHeight()
+ .clickable {
+ component.loadFiles.loadFiles { image ->
+ println("Loaded camera image + " + image)
+ mutableFrontIdBitmapState.value = image
+ }
+ }
+ .drawBehind {
+ drawRoundRect(color = color, style = stroke)
+ }
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth(0.5f)
+ .padding(start = 5.dp)
+ ) {
+ Text(
+ text = "Front Side of your",
+ fontSize = 10.sp,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "National ID/Passport",
+ fontSize = 10.sp,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "Upload front side",
+ fontSize = 10.sp
+ )
+ Text(
+ text = "A front picture of your National ID/Passport",
+ fontSize = 10.sp,
+ style =MaterialTheme.typography.bodySmall
+ )
+
+ }
+ if (mutableFrontIdBitmapState.value == null) {
+ Image(
+ painter = painterResource(Res.drawable.id_card),
+ contentDescription = "Take photo",
+ contentScale = ContentScale.FillBounds,
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .size(70.dp)
+ .clickable {
+ component.loadFiles.loadFiles { image ->
+ println("Loaded camera image + " + image)
+ mutableFrontIdBitmapState.value = image
+ }
+ }
+ )
+ } else {
+ mutableFrontIdBitmapState.value.let { image ->
+ if (image != null) {
+ Image(
+ bitmap = image,
+ contentDescription = null,
+ modifier = Modifier
+ .size(150.dp)
+ .padding(1.dp),
+ alignment = Alignment.CenterEnd
+ )
+ }
+ }
+ }
+ }
+ }
+ Box(
+ Modifier
+ .fillMaxWidth()
+ .padding(top = 16.dp)
+ .wrapContentHeight()
+ .clickable {
+ component.loadFiles.loadFiles { image ->
+ println("Loaded camera image + " + image)
+ mutableBackIdBitmapState.value = image
+ }
+ }
+ .drawBehind {
+ drawRoundRect(color = color, style = stroke)
+ }
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Column(
+ modifier = Modifier
+ .fillMaxWidth(0.5f)
+ .padding(start = 5.dp)
+ ) {
+ Text(
+ text = "Back Side of your",
+ fontSize = 10.sp,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "National ID/Passport",
+ fontSize = 10.sp,
+ color = MaterialTheme.colorScheme.primary
+ )
+ Text(
+ text = "Upload back side",
+ fontSize = 10.sp
+ )
+ Text(
+ text = "A back picture of your National ID/Passport",
+ fontSize = 10.sp,
+ style =MaterialTheme.typography.bodySmall
+ )
+
+ }
+ if (mutableBackIdBitmapState.value == null) {
+ Image(
+ painter = painterResource(Res.drawable.id_card),
+ contentDescription = "Take photo",
+ contentScale = ContentScale.FillBounds,
+ modifier = Modifier
+ .padding(end = 10.dp)
+ .size(70.dp)
+ .clickable {
+ component.loadFiles.loadFiles { image ->
+ println("Loaded camera image + " + image)
+ mutableBackIdBitmapState.value = image
+ }
+ }
+ )
+ } else {
+ mutableBackIdBitmapState.value.let { image ->
+ if (image != null) {
+ Image(
+ bitmap = image,
+ contentDescription = null,
+ modifier = Modifier
+ .size(150.dp)
+ .padding(1.dp),
+ alignment = Alignment.CenterEnd
+ )
+ }
+
+ }
+
+ }
+ }
+ }
+ }
+ item {
+ Row(modifier = Modifier.padding(top = 20.dp, bottom = 20.dp)) {
+
+ }
+ }
+
+ }
+ }
+}
+
+
diff --git a/composeApp/src/commonMain/kotlin/about/DefaultAboutComponent.kt b/composeApp/src/commonMain/kotlin/about/DefaultAboutComponent.kt
new file mode 100644
index 0000000..5541cb8
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/about/DefaultAboutComponent.kt
@@ -0,0 +1,21 @@
+package about
+
+import PlatformSpecific
+import com.arkivanov.decompose.ComponentContext
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+class DefaultAboutComponent(
+ componentContext: ComponentContext,
+ private val onShowWelcome: () -> Unit,
+
+) : AboutComponent, ComponentContext by componentContext, KoinComponent {
+ override val loadFiles: PlatformSpecific by inject()
+ override fun onUpdateGreetingText() {
+ TODO("Not yet implemented")
+ }
+
+ override fun onBackClicked() {
+ TODO("Not yet implemented")
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/buy/BuyComponent.kt b/composeApp/src/commonMain/kotlin/buy/BuyComponent.kt
new file mode 100644
index 0000000..682abf3
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/buy/BuyComponent.kt
@@ -0,0 +1,9 @@
+package buy
+
+interface BuyComponent {
+
+ fun onUpdateGreetingText()
+ fun onBackClicked()
+
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/buy/BuyContent.kt b/composeApp/src/commonMain/kotlin/buy/BuyContent.kt
new file mode 100644
index 0000000..4454f82
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/buy/BuyContent.kt
@@ -0,0 +1,215 @@
+package buy
+
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.lazy.LazyColumn
+import androidx.compose.material3.ElevatedCard
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FilledTonalButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import decomposeapp.composeapp.generated.resources.CoffeeCup
+import decomposeapp.composeapp.generated.resources.Res
+import decomposeapp.composeapp.generated.resources.framea
+import decomposeapp.composeapp.generated.resources.frameb
+import org.jetbrains.compose.resources.ExperimentalResourceApi
+import org.jetbrains.compose.resources.painterResource
+
+@OptIn(ExperimentalMaterial3Api::class, ExperimentalResourceApi::class)
+@Composable
+fun FeedsContent(
+ component: BuyComponent,
+ modifier: Modifier = Modifier
+) {
+ Scaffold(topBar = {
+ TopAppBar(title = {
+ Text(
+ text = "Buy",
+ fontSize = 15.sp
+ )
+ })
+ }) { innerPadding ->
+ Column(
+ Modifier
+ .padding(innerPadding)
+ ) {
+ LazyColumn(modifier = Modifier.padding(start = 16.dp, end = 16.dp)) {
+ item {
+ Row(
+ modifier = Modifier
+ .padding(top = 10.dp)
+ .fillParentMaxHeight(0.3f),
+ horizontalArrangement = Arrangement.Center,
+ ) {
+ ElevatedCardExample()
+ }
+ Text(
+ text = "Cappucino",
+ style = MaterialTheme.typography.titleMedium,
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Text(
+ text = "with Chocolate",
+ style = MaterialTheme.typography.titleMedium,
+ )
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Row() {
+ Text(text = "4.8 (230)",
+ style = MaterialTheme.typography.titleSmall)
+ }
+ Row(horizontalArrangement = Arrangement.spacedBy(10.dp)) {
+ Image(
+ painter = painterResource(Res.drawable.framea),
+ contentDescription = "profile Picture",
+ contentScale = ContentScale.Fit,
+ modifier = Modifier.size(50.dp)
+ )
+ Image(
+ painter = painterResource(Res.drawable.frameb),
+ contentDescription = "profile Picture",
+ contentScale = ContentScale.Fit,
+ modifier = Modifier.size(50.dp)
+ )
+ }
+ }
+ Text(
+ text = "Description",
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Text(
+ text = "A cappuccino is an approximately 150 ml (5 oz) beverage, with 25 ml of espresso coffee and 85ml of fresh milk the fo.. Read More",
+ fontSize = 12.sp,
+ style = MaterialTheme.typography.bodyMedium,
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Text(
+ text = "Size",
+ fontSize = 12.sp,
+ style = MaterialTheme.typography.labelMedium,
+ modifier = Modifier.padding(top = 10.dp)
+ )
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 10.dp),
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ FilledTonalButtonExample(
+ onClick = {},
+ label = "S"
+ )
+ FilledTonalButtonExample(
+ onClick = {},
+ label = "M"
+ )
+ FilledTonalButtonExample(
+ onClick = {},
+ label = "L"
+ )
+
+ }
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 10.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Column() {
+ Text(
+ text = "Price"
+ )
+ Text(
+ text = "$4.53"
+ )
+ }
+ Column() {
+ Text(
+ text = "Price"
+ )
+ Text(
+ text = "$10.53"
+ )
+ }
+ Column() {
+ Text(
+ text = "Price"
+ )
+ Text(
+ text = "$20.53"
+ )
+ }
+ }
+ Row(
+ modifier = Modifier.fillMaxWidth()
+ .padding(top = 10.dp),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ FilledTonalButtonExample(
+ onClick = {},
+ label = " Buy Now "
+ )
+
+ }
+ }
+ }
+ item {
+ Spacer(modifier = Modifier.padding(bottom = 100.dp))
+ }
+ }
+ }
+ }
+}
+
+@OptIn(ExperimentalResourceApi::class)
+@Composable
+fun ElevatedCardExample() {
+ ElevatedCard() {
+ Column() {
+ Box(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Image(
+ painter = painterResource(Res.drawable.CoffeeCup),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth,
+ modifier = Modifier.fillMaxSize()
+ )
+
+ }
+ }
+ }
+}
+
+@Composable
+fun FilledTonalButtonExample(
+ onClick: () -> Unit,
+ label: String
+) {
+ FilledTonalButton(onClick = { onClick() }) {
+ Text(text = label)
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/buy/DefautBuyComponent.kt b/composeApp/src/commonMain/kotlin/buy/DefautBuyComponent.kt
new file mode 100644
index 0000000..a698420
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/buy/DefautBuyComponent.kt
@@ -0,0 +1,18 @@
+package buy
+
+import com.arkivanov.decompose.ComponentContext
+
+class DefautBuyComponent(
+ componentContext: ComponentContext,
+ private val onShowWelcome: () -> Unit,
+) : BuyComponent, ComponentContext by componentContext {
+
+
+ override fun onUpdateGreetingText() {
+ TODO("Not yet implemented")
+ }
+
+ override fun onBackClicked() {
+ TODO("Not yet implemented")
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/di/AppModule.kt b/composeApp/src/commonMain/kotlin/di/AppModule.kt
new file mode 100644
index 0000000..f973407
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/AppModule.kt
@@ -0,0 +1,18 @@
+package di
+
+import PlatformSpecific
+import org.koin.core.context.startKoin
+import org.koin.dsl.KoinAppDeclaration
+import org.koin.dsl.module
+
+
+fun initKoin(enableNetworkLogs: Boolean = false, platform: PlatformSpecific?, appDeclaration: KoinAppDeclaration = {}) = startKoin {
+ appDeclaration()
+ modules(
+ networkModule(enableNetworkLogs,platform),
+ module {
+ factory { platform }
+ single { platform }
+ }
+ )
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/di/NetworkModule.kt b/composeApp/src/commonMain/kotlin/di/NetworkModule.kt
new file mode 100644
index 0000000..f263154
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/di/NetworkModule.kt
@@ -0,0 +1,11 @@
+package di
+import org.koin.core.module.Module
+import org.koin.dsl.module
+import PlatformSpecific
+
+val networkModule: (enableLogging: Boolean, platform: PlatformSpecific?) -> Module get() = { enableLogging, platform ->
+ module {
+ single { enableLogging }
+ single { platform }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/home/DefaultHomeComponent.kt b/composeApp/src/commonMain/kotlin/home/DefaultHomeComponent.kt
new file mode 100644
index 0000000..6e5d665
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/home/DefaultHomeComponent.kt
@@ -0,0 +1,15 @@
+package home
+
+import com.arkivanov.decompose.ComponentContext
+
+
+class DefaultHomeComponent(
+ private val componentContext: ComponentContext,
+ private val onFinished: () -> Unit,
+) : HomeComponent, ComponentContext by componentContext {
+ override fun onUpdateGreetingText() {
+ }
+ override fun onBackClicked() {
+ onFinished()
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/home/HomeComponent.kt b/composeApp/src/commonMain/kotlin/home/HomeComponent.kt
new file mode 100644
index 0000000..b8138aa
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/home/HomeComponent.kt
@@ -0,0 +1,9 @@
+package home
+
+interface HomeComponent {
+
+ fun onUpdateGreetingText()
+ fun onBackClicked()
+
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/home/HomeContent.kt b/composeApp/src/commonMain/kotlin/home/HomeContent.kt
new file mode 100644
index 0000000..a1b94b6
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/home/HomeContent.kt
@@ -0,0 +1,300 @@
+package home
+
+import androidx.compose.foundation.ExperimentalFoundationApi
+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.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.width
+import androidx.compose.foundation.lazy.LazyRow
+import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
+import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
+import androidx.compose.foundation.pager.rememberPagerState
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Search
+import androidx.compose.material.icons.outlined.Tune
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.Card
+import androidx.compose.material3.ElevatedButton
+import androidx.compose.material3.ElevatedCard
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.FilledTonalButton
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.material3.TopAppBarDefaults
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.unit.dp
+import decomposeapp.composeapp.generated.resources.CoffeeCup
+import decomposeapp.composeapp.generated.resources.Res
+import decomposeapp.composeapp.generated.resources.imagee
+import decomposeapp.composeapp.generated.resources.img
+import org.jetbrains.compose.resources.ExperimentalResourceApi
+import org.jetbrains.compose.resources.painterResource
+import theme.buttonColor
+
+@OptIn(
+ ExperimentalResourceApi::class, ExperimentalFoundationApi::class,
+ ExperimentalMaterial3Api::class
+)
+@Composable
+fun WelcomeContent(
+ component: HomeComponent,
+ modifier: Modifier = Modifier
+) {
+ val pagerState = rememberPagerState(pageCount = {
+ 10
+ })
+ Scaffold(
+ modifier = Modifier
+ .fillMaxSize(),
+ topBar = {
+ TopAppBar(
+ title = {
+ Row(modifier = Modifier.background(color = MaterialTheme.colorScheme.primary)) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(start = 16.dp, end = 16.dp, top = 10.dp),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ ) {
+ Column() {
+ Text(
+ text = "Location",
+ style = MaterialTheme.typography.labelSmall,
+ color = MaterialTheme.colorScheme.onSecondaryContainer
+ )
+ Text(
+ text = "Dennis",
+ style = MaterialTheme.typography.titleSmall,
+ color = MaterialTheme.colorScheme.onSecondaryContainer
+ )
+ }
+ //open file picker and set profile picture
+
+
+ Image(
+ painter = painterResource(Res.drawable.img),
+ contentDescription = "profile Picture",
+ modifier = Modifier
+ .width(44.dp)
+ .height(44.dp)
+ )
+ }
+ }
+
+ },
+ colors = TopAppBarDefaults.topAppBarColors(containerColor = MaterialTheme.colorScheme.primary)
+ )
+ },
+
+ ) { innePadding ->
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding()
+ ) {
+ Column(modifier = Modifier.padding(innePadding)) {
+ Box() {
+ Column(
+ modifier = Modifier
+ .background(color = MaterialTheme.colorScheme.primary)
+ .fillMaxHeight(0.3f)
+ ) {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 28.dp, start = 16.dp, end = 16.dp)
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Box(
+ modifier = Modifier.padding(
+ top = 17.dp,
+ bottom = 17.dp,
+ start = 16.dp
+ )
+ ) {
+ Row() {
+ Icon(
+ Icons.Outlined.Search,
+ contentDescription = "Search"
+ )
+ Text(
+ modifier = Modifier.padding(start = 1.dp),
+ text = "Search Coffee",
+ style = MaterialTheme.typography.bodySmall
+ )
+ }
+ }
+ Icon(
+ Icons.Outlined.Tune,
+ contentDescription = "filter",
+ modifier = Modifier
+ .size(40.dp)
+ .background(
+ color = MaterialTheme.colorScheme.tertiary,
+ shape = RoundedCornerShape(14.dp)
+ ),
+ tint = MaterialTheme.colorScheme.onSecondaryContainer
+ )
+ }
+ }
+ }
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .fillMaxHeight(0.41f)
+ .padding(top = 110.dp, start = 16.dp, end = 16.dp),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ Card(
+ modifier = Modifier
+ .fillMaxWidth()
+ .fillMaxHeight(),
+ shape = RoundedCornerShape(16.dp),
+ ) {
+ Box(
+ modifier = Modifier.fillMaxSize(),
+ contentAlignment = Alignment.Center
+ ) {
+
+ Image(
+ painter = painterResource(Res.drawable.imagee),
+ contentDescription = null,
+ contentScale = ContentScale.Crop,
+ modifier = Modifier
+ .matchParentSize()
+ )
+ Column() {
+ Row(
+ modifier = Modifier
+ .padding(start = 16.dp)
+ ) {
+ ElevatedButtonExample()
+ }
+
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.Start,
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Text(
+ text = "Buy one get one FREE",
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.onSecondaryContainer,
+ modifier = Modifier
+ .fillMaxWidth(0.5f)
+ .padding(start = 16.dp),
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+ Column() {
+ LazyRow(
+ modifier = Modifier
+ .padding(top = 20.dp, start = 16.dp, end = 16.dp)
+ ) {
+ items(5) {
+ FilledTonalButton { }
+ Spacer(modifier = Modifier.padding(start = 5.dp))
+ }
+ }
+ LazyVerticalStaggeredGrid(
+ columns = StaggeredGridCells.Fixed(2),
+ verticalItemSpacing = 10.dp,
+ horizontalArrangement = Arrangement.spacedBy(24.dp),
+ content = {
+ items(10) {
+ ProductsCard()
+ }
+ },
+ modifier = Modifier
+ .fillMaxSize()
+ .padding(top = 20.dp, start = 16.dp, end = 16.dp)
+ )
+ }
+ }
+ }
+ }
+}
+
+@Composable
+fun FilledTonalButton(onClick: () -> Unit) {
+ FilledTonalButton(onClick = { onClick() }) {
+ Text("Cappuccino",
+ style = MaterialTheme.typography.labelLarge)
+ }
+}
+
+@OptIn(ExperimentalResourceApi::class)
+@Composable
+fun ProductsCard() {
+ ElevatedCard() {
+ Column() {
+ Box(
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Image(
+ painter = painterResource(Res.drawable.CoffeeCup),
+ contentDescription = null,
+ contentScale = ContentScale.FillWidth,
+ modifier = Modifier.fillMaxSize()
+ )
+ Column() {
+ Text(
+ text = "6.5",
+ modifier = Modifier.padding(start = 12.dp),
+ color = MaterialTheme.colorScheme.onSecondaryContainer,
+ style = MaterialTheme.typography.labelMedium
+ )
+ }
+ }
+ Column(modifier = Modifier.padding(top = 12.dp, start = 12.dp)) {
+ Text(text = "Cappucino",
+ style = MaterialTheme.typography.bodyMedium)
+ Text(text = "with Chocolate",
+ style = MaterialTheme.typography.bodyMedium)
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween
+ ) {
+ Text(text = "$ 4.53",
+ style = MaterialTheme.typography.labelLarge)
+ }
+ }
+ }
+
+ }
+}
+
+@Composable
+fun ElevatedButtonExample() {
+ ElevatedButton(modifier = Modifier
+ .height(35.dp),
+ colors = ButtonDefaults.buttonColors(containerColor = buttonColor),
+ onClick = { }) {
+ Text("Promo")
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/notifications/DefaultNotificationComponent.kt b/composeApp/src/commonMain/kotlin/notifications/DefaultNotificationComponent.kt
new file mode 100644
index 0000000..13d32ae
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/notifications/DefaultNotificationComponent.kt
@@ -0,0 +1,20 @@
+package notifications
+
+import PlatformSpecific
+import com.arkivanov.decompose.ComponentContext
+import org.koin.core.component.KoinComponent
+import org.koin.core.component.inject
+
+
+class DefaultNotificationComponent(
+ componentContext: ComponentContext,
+ private val onShowWelcome: () -> Unit,
+) : NotificationComponent, ComponentContext by componentContext, KoinComponent {
+ override val platformSpecific: PlatformSpecific by inject()
+ override fun onUpdateGreetingText() {
+ TODO("Not yet implemented")
+ }
+ override fun onBackClicked() {
+ TODO("Not yet implemented")
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/notifications/NotificationComponent.kt b/composeApp/src/commonMain/kotlin/notifications/NotificationComponent.kt
new file mode 100644
index 0000000..bccd331
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/notifications/NotificationComponent.kt
@@ -0,0 +1,12 @@
+package notifications
+
+import PlatformSpecific
+
+
+interface NotificationComponent {
+ val platformSpecific: PlatformSpecific
+ fun onUpdateGreetingText()
+ fun onBackClicked()
+
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/notifications/NotificationContent.kt b/composeApp/src/commonMain/kotlin/notifications/NotificationContent.kt
new file mode 100644
index 0000000..2d7460c
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/notifications/NotificationContent.kt
@@ -0,0 +1,55 @@
+package notifications
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.Call
+import androidx.compose.material3.ElevatedButton
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.material3.TopAppBar
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun NotificationContent(component: NotificationComponent, modifier: Modifier = Modifier) {
+ Scaffold(topBar = {
+ TopAppBar(title = { Text(text = "Notify", fontSize = 15.sp) })
+ }) { paddingValues ->
+ Column(
+ modifier = Modifier.padding(paddingValues)
+ .fillMaxSize()
+ ) {
+ Column(modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp)) {
+ ElevatedButton(modifier = Modifier
+ .fillMaxWidth(), onClick = {
+ component.platformSpecific.launchDialer("+2547897567")
+
+ }) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ Icon(
+ Icons.Default.Call,
+ contentDescription = "Call Icon",
+ tint = Color.Green,
+ modifier = Modifier.padding(1.dp)
+ )
+ Text(text = "Call")
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/rootBottomStack/DefaultRootBottomComponent.kt b/composeApp/src/commonMain/kotlin/rootBottomStack/DefaultRootBottomComponent.kt
new file mode 100644
index 0000000..de9cb58
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/rootBottomStack/DefaultRootBottomComponent.kt
@@ -0,0 +1,148 @@
+package rootBottomStack
+
+import about.AboutComponent
+import about.DefaultAboutComponent
+import buy.BuyComponent
+import buy.DefautBuyComponent
+import com.arkivanov.decompose.ComponentContext
+import com.arkivanov.decompose.router.stack.ChildStack
+import com.arkivanov.decompose.router.stack.StackNavigation
+import com.arkivanov.decompose.router.stack.active
+import com.arkivanov.decompose.router.stack.bringToFront
+import com.arkivanov.decompose.router.stack.childStack
+import com.arkivanov.decompose.value.Value
+import com.arkivanov.essenty.lifecycle.Lifecycle
+import home.DefaultHomeComponent
+import home.HomeComponent
+import kotlinx.serialization.Serializable
+import notifications.DefaultNotificationComponent
+import notifications.NotificationComponent
+
+
+class DefaultRootBottomComponent(
+ componentContext: ComponentContext
+
+) : RootBottomComponent, ComponentContext by componentContext {
+ private val navigationBottomStackNavigation = StackNavigation()
+
+ private val _childStackBottom =
+ childStack(
+ source = navigationBottomStackNavigation,
+ serializer = ConfigBottom.serializer(),
+ initialConfiguration = ConfigBottom.Welcome,
+ handleBackButton = true,
+ childFactory = ::createChildBottom,
+ key = "authStack"
+ )
+
+ override val childStackBottom: Value> =
+ _childStackBottom
+
+
+ private fun createChildBottom(
+ config: ConfigBottom,
+ componentContext: ComponentContext
+ ): RootBottomComponent.ChildBottom =
+ when (config) {
+
+ is ConfigBottom.Welcome -> RootBottomComponent.ChildBottom.WelcomeChild(
+ welcomeComponent(componentContext)
+ )
+
+ is ConfigBottom.Feeds -> RootBottomComponent.ChildBottom.FeedsChild(
+ feedsComponent(componentContext)
+ )
+
+ is ConfigBottom.Message -> RootBottomComponent.ChildBottom.MessageChild(
+ messageComponent(componentContext)
+ )
+
+ is ConfigBottom.Notification -> RootBottomComponent.ChildBottom.NotificationsChild(
+ notificationComponent(componentContext)
+ )
+ }
+
+
+ private fun welcomeComponent(componentContext: ComponentContext): HomeComponent =
+ DefaultHomeComponent(
+ componentContext = componentContext,
+ onFinished = {
+
+ }
+
+ )
+
+ private fun feedsComponent(componentContext: ComponentContext): BuyComponent =
+ DefautBuyComponent(
+ componentContext = componentContext,
+ onShowWelcome = {
+
+ }
+
+ )
+
+ private fun messageComponent(componentContext: ComponentContext): AboutComponent =
+ DefaultAboutComponent(
+ componentContext = componentContext,
+ onShowWelcome = {
+
+ }
+
+ )
+
+ private fun notificationComponent(componentContext: ComponentContext): NotificationComponent =
+ DefaultNotificationComponent(
+ componentContext = componentContext,
+ onShowWelcome = {
+
+ }
+
+ )
+
+ override fun openHome() {
+ navigationBottomStackNavigation.bringToFront(ConfigBottom.Welcome)
+ }
+
+ override fun openFeeds() {
+ navigationBottomStackNavigation.bringToFront(ConfigBottom.Feeds)
+ }
+
+ override fun openMessage() {
+ navigationBottomStackNavigation.bringToFront(ConfigBottom.Message)
+ }
+
+ override fun openNotifications() {
+ navigationBottomStackNavigation.bringToFront(ConfigBottom.Notification)
+ }
+
+ @Serializable
+ private sealed class ConfigBottom {
+ @Serializable
+ data object Welcome : ConfigBottom()
+
+ @Serializable
+ data object Feeds : ConfigBottom()
+
+ @Serializable
+ data object Message : ConfigBottom()
+
+ @Serializable
+ data object Notification : ConfigBottom()
+
+ }
+
+ init {
+ lifecycle.subscribe(object : Lifecycle.Callbacks {
+ override fun onResume() {
+ when (childStackBottom.active.configuration) {
+ is ConfigBottom.Message -> {
+ super.onResume()
+ }
+
+ }
+ }
+ })
+
+ }
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomComponent.kt b/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomComponent.kt
new file mode 100644
index 0000000..a913b44
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomComponent.kt
@@ -0,0 +1,26 @@
+package rootBottomStack
+
+import com.arkivanov.decompose.router.stack.ChildStack
+import com.arkivanov.decompose.value.Value
+import buy.BuyComponent
+import about.AboutComponent
+import notifications.NotificationComponent
+import home.HomeComponent
+
+
+interface RootBottomComponent {
+ val childStackBottom: Value>
+ fun openHome()
+ fun openFeeds()
+ fun openMessage()
+ fun openNotifications()
+
+ sealed class ChildBottom {
+ class WelcomeChild(val component: HomeComponent) : ChildBottom()
+ class FeedsChild(val component: BuyComponent) : ChildBottom()
+ class MessageChild(val component: AboutComponent) : ChildBottom()
+ class NotificationsChild(val component: NotificationComponent) : ChildBottom()
+ }
+
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomScreen.kt b/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomScreen.kt
new file mode 100644
index 0000000..c186630
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/rootBottomStack/RootBottomScreen.kt
@@ -0,0 +1,120 @@
+package rootBottomStack
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Badge
+import androidx.compose.material.icons.outlined.Home
+import androidx.compose.material.icons.outlined.Notifications
+import androidx.compose.material.icons.outlined.ShoppingCart
+import androidx.compose.material3.BottomAppBar
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.NavigationBarItem
+import androidx.compose.material3.NavigationBarItemDefaults
+import androidx.compose.material3.Scaffold
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import com.arkivanov.decompose.extensions.compose.jetbrains.stack.Children
+import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.fade
+import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.plus
+import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.scale
+import com.arkivanov.decompose.extensions.compose.jetbrains.stack.animation.stackAnimation
+import buy.FeedsContent
+import about.MessageContent
+import notifications.NotificationContent
+import home.WelcomeContent
+
+data class ScreensBottom(val name: String, val openScreen: () -> Unit, val isSelected: Boolean)
+
+@Composable
+fun RootBottomScreen(component: RootBottomComponent, modifier: Modifier = Modifier) {
+ var selectedItem by remember { mutableIntStateOf(0) }
+ val screens by remember {
+ mutableStateOf(
+ listOf(
+ ScreensBottom("Home", component::openHome, false),
+ ScreensBottom("Buy", component::openFeeds, false),
+ ScreensBottom("About", component::openMessage, false),
+ ScreensBottom("Notify", component::openNotifications, false)
+ )
+ )
+ }
+ Scaffold(
+ bottomBar = {
+ BottomAppBar(
+ modifier = Modifier.fillMaxWidth(),
+ actions = {
+ screens.forEachIndexed { index, screensBottom ->
+ NavigationBarItem(
+ icon = {
+ when (screensBottom.name) {
+ "Home" -> Icon(Icons.Outlined.Home, contentDescription = null)
+ "Buy" -> Icon(
+ Icons.Outlined.ShoppingCart,
+ contentDescription = null
+ )
+
+ "About" -> Icon(
+ Icons.Outlined.Badge,
+ contentDescription = null
+ )
+
+ "Notify" -> Icon(
+ Icons.Outlined.Notifications,
+ contentDescription = null
+ )
+ }
+ },
+ label = {
+ Text(
+ text = screensBottom.name,
+ style = MaterialTheme.typography.labelLarge,
+ fontWeight = FontWeight.Light
+ )
+ },
+ selected = selectedItem == index,
+ onClick = {
+ selectedItem = index
+ screensBottom.openScreen()
+ },
+ colors = NavigationBarItemDefaults.colors(selectedIconColor = MaterialTheme.colorScheme.primary)
+ )
+ }
+ }
+ )
+
+ },
+ content = { innerpadding ->
+ Column(modifier = Modifier.padding(innerpadding)) {
+ Children(
+ stack = component.childStackBottom,
+ modifier = modifier,
+ animation = stackAnimation(fade() + scale()),
+ ) {
+ when (val child = it.instance) {
+ is RootBottomComponent.ChildBottom.WelcomeChild -> WelcomeContent(component = child.component)
+ is RootBottomComponent.ChildBottom.FeedsChild -> FeedsContent(component = child.component)
+ is RootBottomComponent.ChildBottom.MessageChild -> MessageContent(
+ component = child.component,
+ modifier
+ )
+
+ is RootBottomComponent.ChildBottom.NotificationsChild -> NotificationContent(
+ component = child.component
+ )
+ }
+ }
+ }
+ })
+
+
+}
\ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/theme/Colors.kt b/composeApp/src/commonMain/kotlin/theme/Colors.kt
new file mode 100644
index 0000000..72968aa
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/theme/Colors.kt
@@ -0,0 +1,40 @@
+
+package theme
+
+import androidx.compose.ui.graphics.Color
+
+val PrimaryColor = Color(0xff214E78)
+val PrimaryLightColor = PrimaryColor.copy(alpha = 0.75f)
+
+val SecondaryColor = Color(0xff7C93BE)
+val SecondaryLightColor = SecondaryColor.copy(alpha = 0.75f)
+
+val PrimaryTextColor = Color(0xffffffff)
+val SecondaryTextColor = Color(0xff000000)
+val customBackGround = Color(0xff262626)
+val SurfaceDark = Color(0xFF161616)
+val SurfaceLight = Color(0xffFFFFFFFF)
+
+val BackgroundLightColor = Color(0xffF1F0F5)
+
+val BackgroundDarkColor = Color(0xff010100)
+
+val ErrorColor = Color(0xFFFF8989)
+val OnErrorColor = Color(0xFF000000)
+
+val iconColor = Color(0xFFC67C4E)
+ val buttonColor = Color(0xffED5151)
+
+const val SessionColor = 0xFfBA4949
+const val ShortBreakColor = 0xFf38858A
+const val LongBreakColor = 0xFf397097
+
+const val Red = 0xFFFF0000
+const val Orange = 0xFFFFA500
+const val Blue = 0xFF0000FF
+const val Green = 0xFF00FF00
+
+const val LightGreen = 0xFF90EE90
+const val Yellow = 0xFFFFFF00
+const val LightBlue = 0xFFADD8E6
+const val Pink = 0xFFFFC0CB
diff --git a/composeApp/src/commonMain/kotlin/theme/Shapes.kt b/composeApp/src/commonMain/kotlin/theme/Shapes.kt
new file mode 100644
index 0000000..802264f
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/theme/Shapes.kt
@@ -0,0 +1,12 @@
+
+package theme
+
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.Shapes
+import androidx.compose.ui.unit.dp
+
+internal val Shapes = Shapes(
+ small = RoundedCornerShape(4.dp),
+ medium = RoundedCornerShape(8.dp),
+ large = RoundedCornerShape(12.dp),
+)
diff --git a/composeApp/src/commonMain/kotlin/theme/Theme.kt b/composeApp/src/commonMain/kotlin/theme/Theme.kt
new file mode 100644
index 0000000..588ed24
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/theme/Theme.kt
@@ -0,0 +1,57 @@
+
+package theme
+
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.darkColorScheme
+import androidx.compose.material3.lightColorScheme
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.graphics.Color
+
+private val LightColors = lightColorScheme(
+ primary = customBackGround,
+ onPrimary = PrimaryTextColor,
+ secondary = SecondaryColor,
+ onSecondary = SecondaryTextColor,
+ tertiary = iconColor,
+ onTertiary = PrimaryTextColor,
+ background = BackgroundLightColor,
+ onBackground = Color.Black,
+ surface = SurfaceLight,
+ onSurface = Color.Black,
+ surfaceVariant = SurfaceLight,
+ onSurfaceVariant = Color.Black,
+ secondaryContainer = PrimaryColor,
+ onSecondaryContainer = Color.White,
+ error = ErrorColor,
+ onError = OnErrorColor,
+)
+
+private val DarkColors = darkColorScheme(
+ primary = customBackGround,
+ onPrimary = PrimaryTextColor,
+ secondary = SecondaryLightColor,
+ onSecondary = SecondaryTextColor,
+ tertiary = iconColor,
+ onTertiary = PrimaryTextColor,
+ background = BackgroundDarkColor,
+ onBackground = Color.White,
+ surface = SurfaceDark,
+ onSurface = Color.White,
+ surfaceVariant = SurfaceDark,
+ onSurfaceVariant = Color.White,
+ secondaryContainer = PrimaryColor,
+ onSecondaryContainer = Color.White,
+ error = ErrorColor,
+ onError = OnErrorColor,
+)
+
+@Composable
+internal fun ComposeExperimentalTheme(useDarkTheme: Boolean = isSystemInDarkTheme(), content: @Composable () -> Unit) {
+ val autoColors = if (useDarkTheme)LightColors else LightColors
+ MaterialTheme(
+ colorScheme = autoColors,
+ shapes = Shapes,
+ content = content,
+ )
+}
diff --git a/composeApp/src/iosMain/kotlin/MainViewController.kt b/composeApp/src/iosMain/kotlin/MainViewController.kt
new file mode 100644
index 0000000..4f05df5
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/MainViewController.kt
@@ -0,0 +1,39 @@
+import androidx.compose.runtime.CompositionLocalProvider
+import androidx.compose.runtime.InternalComposeApi
+import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.platform.LocalSafeArea
+import androidx.compose.ui.platform.PlatformInsets
+import androidx.compose.ui.unit.dp
+import com.arkivanov.decompose.DefaultComponentContext
+import com.arkivanov.essenty.lifecycle.LifecycleRegistry
+import com.moriatsushi.insetsx.WindowInsetsUIViewController
+import di.initKoin
+import platform.UIKit.UIViewController
+import rootBottomStack.DefaultRootBottomComponent
+import theme.ComposeExperimentalTheme
+
+@OptIn(ExperimentalComposeUiApi::class, InternalComposeApi::class)
+@Suppress("unused", "FunctionName")
+fun MainViewController(
+ lifecycle: LifecycleRegistry,
+ topSafeArea: Float,
+ bottomSafeArea: Float,
+): UIViewController {
+ val defaultComponentCtx = DefaultComponentContext(lifecycle = lifecycle)
+ val root = DefaultRootBottomComponent(
+ componentContext = defaultComponentCtx
+ )
+ initKoin(enableNetworkLogs = true, platform = PlatformSpecific())
+ return WindowInsetsUIViewController {
+ val density = LocalDensity.current
+ val topSafeAreaDp = with(density) { topSafeArea.toDp() }
+ val bottomSafeAreaDp = with(density) { bottomSafeArea.toDp() }
+ val safeArea = PlatformInsets(top = topSafeAreaDp + 10.dp, bottom = bottomSafeAreaDp)
+ CompositionLocalProvider(LocalSafeArea provides safeArea) {
+ ComposeExperimentalTheme {
+ App(root)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/composeApp/src/iosMain/kotlin/Platform.ios.kt b/composeApp/src/iosMain/kotlin/Platform.ios.kt
new file mode 100644
index 0000000..5cef987
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/Platform.ios.kt
@@ -0,0 +1,7 @@
+import platform.UIKit.UIDevice
+
+class IOSPlatform: Platform {
+ override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
+}
+
+actual fun getPlatform(): Platform = IOSPlatform()
\ No newline at end of file
diff --git a/composeApp/src/iosMain/kotlin/PlatformSpecific.kt b/composeApp/src/iosMain/kotlin/PlatformSpecific.kt
new file mode 100644
index 0000000..c1976e0
--- /dev/null
+++ b/composeApp/src/iosMain/kotlin/PlatformSpecific.kt
@@ -0,0 +1,16 @@
+import androidx.compose.ui.graphics.ImageBitmap
+
+actual open class PlatformSpecific{
+ actual fun loadFiles(callback: (ImageBitmap?) -> Unit) {
+ //convert an image to a Imagebitmap equivalent in swift
+ }
+
+ actual fun loadImages(callback: (ImageBitmap?) -> Unit) {
+ }
+
+ actual fun launchDialer(phoneNumber: String) {
+
+ //swift launch dialer implementation
+ }
+
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index b085ecd..25698c8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,24 +1,23 @@
-#Gradle
-org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
-
-#Kotlin
kotlin.code.style=official
-#MPP
-kotlin.mpp.stability.nowarn=true
-kotlin.mpp.enableCInteropCommonization=true
-kotlin.mpp.androidSourceSetLayoutVersion=2
+#Gradle
+org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
-#Compose
-org.jetbrains.compose.experimental.uikit.enabled=true
#Android
+android.nonTransitiveRClass=true
android.useAndroidX=true
-android.targetSdk=34
-android.compileSdk=34
-android.minSdk=24
+
+#MPP
+kotlin.mpp.androidSourceSetLayoutVersion=2
+kotlin.mpp.enableCInteropCommonization=true
+
+#Development
+development=true
#Versions
+#//To update
kotlin.version=1.9.20
-agp.version=8.0.2
-compose.version=1.5.11
+agp.version=8.1.1
+compose.version=1.5.10
+sqldelight.version=2.0.0
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..cfc3ed2
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,130 @@
+[versions]
+agp = "8.1.1"
+android-compileSdk = "34"
+android-minSdk = "24"
+android-targetSdk = "34"
+androidx-activityCompose = "1.8.2"
+androidx-constraintlayout = "2.1.4"
+androidx-core-ktx = "1.12.0"
+androidx-espresso-core = "3.5.1"
+androidx-material = "1.11.0"
+androidx-test-junit = "1.1.5"
+compose = "1.5.11"
+compose-plugin = "1.6.0"
+junit = "4.13.2"
+kotlin = "1.9.21"
+serialization = "1.6.0"
+moko = "0.23.0"
+moko-graphics = "0.9.0"
+mviKotlin = "3.2.1"
+logbackClassic = "1.2.11"
+sqlDelight = "2.0.0"
+koin = "3.5.0"
+ktor = "2.3.7"
+decompose = "2.2.2"
+essenty = "1.3.0"
+parcelizeDarwin = "0.2.3"
+jetbrainsCompose = "1.5.10"
+jetbrainsKotlinxCoroutines = "1.8.0"
+jetbrainsBinaryCompatibilityValidator = "0.13.2"
+androidxCore = "1.12.0"
+androidxAppcompat = "1.6.1"
+androidxLifecycle = "2.7.0"
+androidxActivity = "1.8.2"
+androidxFragment = "1.6.2"
+androidxTestCore = "1.5.0"
+extensionJetbrains = "2.0.0-compose-experimental-alpha-02"
+russhwolf = "1.1.0"
+gms = "4.4.0"
+analytics = "21.3.0"
+crashlytics = "18.3.2"
+
+
+[libraries]
+kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" }
+kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" }
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" }
+androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" }
+androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" }
+androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" }
+androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" }
+androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
+compose-ui-tooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose" }
+compose-ui-tooling-preview = { module = "androidx.compose.ui:ui-tooling-preview", version.ref = "compose" }
+
+analytics-firebase = {group = "com.google.firebase", name = "firebase-analytics-ktx", version.ref = "analytics"}
+crashlytics-firebase = {group = "com.google.firebase", name = "firebase-crashlytics-ktx", version.ref = "crashlytics"}
+
+gms-google-services = {group = "com.google.gms", name = "google-services", version.ref = "gms"}
+
+russhwolf-settings-core = {group = "com.russhwolf", name = "multiplatform-settings", version.ref = "russhwolf" }
+russhwolf-settings-serialization = {group = "com.russhwolf", name = "multiplatform-settings-serialization", version.ref = "russhwolf" }
+
+
+#Koin
+koin-android = { group = "io.insert-koin", name = "koin-android", version.ref = "koin" }
+koin-core = { group = "io.insert-koin", name = "koin-core", version.ref = "koin" }
+koin-test = { group = "io.insert-koin", name = "koin-test", version.ref = "koin" }
+
+
+#Decompose
+mvikotlin = { group = "com.arkivanov.mvikotlin", name = "mvikotlin", version.ref = "mviKotlin" }
+mviKotlin-mvikotlinMain = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-main", version.ref = "mviKotlin" }
+mviKotlin-mvikotlinExtensionsCoroutines = { group = "com.arkivanov.mvikotlin", name = "mvikotlin-extensions-coroutines", version.ref = "mviKotlin" }
+decompose = { group = "com.arkivanov.decompose", name = "decompose", version.ref = "decompose" }
+decompose-jetbrains = { group = "com.arkivanov.decompose", name = "extensions-compose-jetbrains", version.ref = "extensionJetbrains" }
+essenty-lifecycle = { group = "com.arkivanov.essenty", name = "lifecycle", version.ref = "essenty" }
+essenty-stateKeeper = { group = "com.arkivanov.essenty", name = "state-keeper", version.ref = "essenty" }
+essenty-instanceKeeper = { group = "com.arkivanov.essenty", name = "instance-keeper", version.ref = "essenty" }
+essenty-backHandler = { group = "com.arkivanov.essenty", name = "back-handler", version.ref = "essenty" }
+parcelizeDarwin-gradlePlug = { group = "com.arkivanov.parcelize.darwin", name = "gradle-plugin", version.ref = "parcelizeDarwin" }
+parcelizeDarwin-runtime = { group = "com.arkivanov.parcelize.darwin", name = "runtime", version.ref = "parcelizeDarwin" }
+#Ktor
+ktor-ClientCore = {group = "io.ktor", name = "ktor-client-core", version.ref = "ktor" }
+ktor-SerializationKotlinxJson = {group = "io.ktor", name = "ktor-serialization-kotlinx-json", version.ref = "ktor" }
+ktor-ClientContentNegotiation = {group = "io.ktor", name = "ktor-client-content-negotiation", version.ref = "ktor" }
+ktor-ClientLogging = {group = "io.ktor", name = "ktor-client-logging", version.ref = "ktor" }
+ktor-ClientAndroid = {group = "io.ktor", name = "ktor-client-android", version.ref = "ktor" }
+ktor-ClientDarwin = {group = "io.ktor", name = "ktor-client-darwin", version.ref = "ktor" }
+#ktor-ClientJava = {group = "io.ktor", name = "ktor-client-java", version.ref = "ktor" }
+#ktor-ClientJs = {group = "io.ktor", name = "ktor-client-js", version.ref = "ktor" }
+
+#Ktor logback
+logbackClassic = { group = "ch.qos.logback", name = "logback-classic", version.ref = "logbackClassic" }
+
+#Sql
+sqlDelight-gradlePlugin = {group = "app.cash.sqldelight", name = "gradle-plugin", version.ref = "sqlDelight" }
+sqlDelight-androidDriver = {group = "app.cash.sqldelight", name = "android-driver", version.ref = "sqlDelight" }
+sqlDelight-sqliteDriver = {group = "app.cash.sqldelight", name = "sqlite-driver", version.ref = "sqlDelight" }
+sqlDelight-nativeDriver = {group = "app.cash.sqldelight", name = "native-driver", version.ref = "sqlDelight" }
+sqlDelight-sqljsDriver = {group = "app.cash.sqldelight", name = "sqljs-driver", version.ref = "sqlDelight" }
+sqlDelight-coroutinesExtensions = {group = "app.cash.sqldelight", name = "coroutines-extensions", version.ref = "sqlDelight" }
+sqlDelight-primitiveAdapters = {group = "app.cash.sqldelight", name = "primitive-adapters", version.ref = "sqlDelight" }
+
+
+androidx-core-coreKtx = { group = "androidx.core", name = "core-ktx", version.ref = "androidxCore" }
+androidx-appcompat-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidxAppcompat" }
+androidx-lifecycle-lifecycleCommonJava8 = { group = "androidx.lifecycle", name = "lifecycle-common-java8", version.ref = "androidxLifecycle" }
+androidx-activity-activityKtx = { group = "androidx.activity", name = "activity-ktx", version.ref = "androidxActivity" }
+androidx-activity-activityCompose = { group = "androidx.activity", name = "activity-compose", version.ref = "androidxActivity" }
+androidx-fragment-fragmentKtx = { group = "androidx.fragment", name = "fragment-ktx", version.ref = "androidxFragment" }
+androidx-test-core = { group = "androidx.test", name = "core", version.ref = "androidxTestCore" }
+
+
+
+jetbrains-compose-composeGradlePlug = { group = "org.jetbrains.compose", name = "compose-gradle-plugin", version.ref = "jetbrainsCompose" }
+jetbrains-kotlinx-binaryCompatibilityValidator = { group = "org.jetbrains.kotlinx", name = "binary-compatibility-validator", version.ref = "jetbrainsBinaryCompatibilityValidator" }
+jetbrains-kotlinx-kotlinxCoroutinesCore = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "jetbrainsKotlinxCoroutines" }
+jetbrains-kotlinx-kotlinxSerializationJson = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "serialization" }
+jetbrains-kotlinx-kotlinxCoroutinesSwing = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-swing", version.ref = "jetbrainsKotlinxCoroutines" }
+
+
+
+
+
+[plugins]
+androidApplication = { id = "com.android.application", version.ref = "agp" }
+androidLibrary = { id = "com.android.library", version.ref = "agp" }
+jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
+kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 7f93135..033e24c 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradlew b/gradlew
index 1aa94a4..fcb6fca 100755
--- a/gradlew
+++ b/gradlew
@@ -83,8 +83,7 @@ done
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
-# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
-APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@@ -145,7 +144,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
+ # shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
@@ -153,7 +152,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
- # shellcheck disable=SC2039,SC3045
+ # shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@@ -202,11 +201,11 @@ fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
-# Collect all arguments for the java command:
-# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
-# and any embedded shellness will be escaped.
-# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
-# treated as '${Hostname}' itself on the command line.
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
diff --git a/iosApp/Configuration/Config.xcconfig b/iosApp/Configuration/Config.xcconfig
index f391597..2e659a0 100644
--- a/iosApp/Configuration/Config.xcconfig
+++ b/iosApp/Configuration/Config.xcconfig
@@ -1,3 +1,3 @@
TEAM_ID=
-BUNDLE_ID=com.myapplication.MyApplication
-APP_NAME=My application
+BUNDLE_ID=org.example.project.DecomposeApp
+APP_NAME=DecomposeApp
\ No newline at end of file
diff --git a/iosApp/iosApp.xcodeproj/project.pbxproj b/iosApp/iosApp.xcodeproj/project.pbxproj
index c852042..48dc62d 100644
--- a/iosApp/iosApp.xcodeproj/project.pbxproj
+++ b/iosApp/iosApp.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 50;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@@ -17,14 +17,14 @@
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 = ""; };
- 7555FF7B242A565900829871 /* My application.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "My application.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 7555FF7B242A565900829871 /* DecomposeApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DecomposeApp.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 */
- F85CB1118929364A9C6EFABC /* Frameworks */ = {
+ B92378962B6B1156000C7307 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -62,7 +62,7 @@
7555FF7C242A565900829871 /* Products */ = {
isa = PBXGroup;
children = (
- 7555FF7B242A565900829871 /* My application.app */,
+ 7555FF7B242A565900829871 /* DecomposeApp.app */,
);
name = Products;
sourceTree = "";
@@ -94,18 +94,20 @@
isa = PBXNativeTarget;
buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */;
buildPhases = (
- 05D91A912A5EF49C00F138EB /* Compile Kotlin */,
+ F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */,
7555FF77242A565900829871 /* Sources */,
+ B92378962B6B1156000C7307 /* Frameworks */,
7555FF79242A565900829871 /* Resources */,
- F85CB1118929364A9C6EFABC /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = iosApp;
+ packageProductDependencies = (
+ );
productName = iosApp;
- productReference = 7555FF7B242A565900829871 /* My application.app */;
+ productReference = 7555FF7B242A565900829871 /* DecomposeApp.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
@@ -124,7 +126,7 @@
};
};
buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */;
- compatibilityVersion = "Xcode 9.3";
+ compatibilityVersion = "Xcode 12.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@@ -132,6 +134,8 @@
Base,
);
mainGroup = 7555FF72242A565900829871;
+ packageReferences = (
+ );
productRefGroup = 7555FF7C242A565900829871 /* Products */;
projectDirPath = "";
projectRoot = "";
@@ -154,7 +158,7 @@
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
- 05D91A912A5EF49C00F138EB /* Compile Kotlin */ = {
+ F36B1CEB2AD83DDC00CB74D5 /* Compile Kotlin Framework */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
@@ -163,14 +167,14 @@
);
inputPaths = (
);
- name = "Compile Kotlin";
+ name = "Compile Kotlin Framework";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:embedAndSignAppleFrameworkForXcode\n";
+ 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 */
@@ -239,7 +243,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 14.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
@@ -295,7 +299,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 14.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
@@ -312,14 +316,13 @@
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
- DEVELOPMENT_TEAM = "${TEAM_ID}";
+ DEVELOPMENT_TEAM = 9Z5F72MRRD;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)\n",
- "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n",
+ "$(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 = 14.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -327,9 +330,7 @@
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
- "shared\n$(inherited)",
- "-framework",
- "shared\n",
+ composeApp,
);
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
PRODUCT_NAME = "${APP_NAME}";
@@ -349,11 +350,10 @@
DEVELOPMENT_TEAM = "${TEAM_ID}";
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = (
- "$(inherited)\n",
- "$(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)\n",
+ "$(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 = 14.1;
+ IPHONEOS_DEPLOYMENT_TARGET = 15.3;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -361,9 +361,7 @@
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
- "shared\n$(inherited)",
- "-framework",
- "shared\n",
+ composeApp,
);
PRODUCT_BUNDLE_IDENTIFIER = "${BUNDLE_ID}${TEAM_ID}";
PRODUCT_NAME = "${APP_NAME}";
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 0000000..18d9810
--- /dev/null
+++ b/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/iosApp/iosApp/Assets.xcassets/Contents.json b/iosApp/iosApp/Assets.xcassets/Contents.json
index 73c0059..4aa7c53 100644
--- a/iosApp/iosApp/Assets.xcassets/Contents.json
+++ b/iosApp/iosApp/Assets.xcassets/Contents.json
@@ -3,4 +3,4 @@
"author" : "xcode",
"version" : 1
}
-}
+}
\ No newline at end of file
diff --git a/iosApp/iosApp/ContentView.swift b/iosApp/iosApp/ContentView.swift
index 64e7056..4647c9f 100644
--- a/iosApp/iosApp/ContentView.swift
+++ b/iosApp/iosApp/ContentView.swift
@@ -1,19 +1,44 @@
import UIKit
import SwiftUI
-import shared
+import ComposeApp
struct ComposeView: UIViewControllerRepresentable {
+
+ private let lifecycle: LifecycleRegistry
+ private let topSafeArea: Float
+ private let bottomSafeArea: Float
+
+ init(lifecycle: LifecycleRegistry, topSafeArea: Float, bottomSafeArea: Float) {
+ self.lifecycle = lifecycle
+ self.topSafeArea = topSafeArea
+ self.bottomSafeArea = bottomSafeArea
+ }
+
func makeUIViewController(context: Context) -> UIViewController {
- Main_iosKt.MainViewController()
+ MainViewControllerKt.MainViewController(
+ lifecycle: lifecycle,
+ topSafeArea: topSafeArea,
+ bottomSafeArea: bottomSafeArea
+ )
}
-
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
}
struct ContentView: View {
+ private let lifecycle: LifecycleRegistry
+ private let topSafeArea: Float
+ private let bottomSafeArea: Float
+
+ init(lifecycle: LifecycleRegistry, topSafeArea: Float, bottomSafeArea: Float) {
+ self.lifecycle = lifecycle
+ self.topSafeArea = topSafeArea
+ self.bottomSafeArea = bottomSafeArea
+ }
var body: some View {
- ComposeView()
- .ignoresSafeArea(.all, edges: .bottom) // Compose has own keyboard handler
+ ComposeView( lifecycle: lifecycle,
+ topSafeArea: topSafeArea,
+ bottomSafeArea: bottomSafeArea)
+ .ignoresSafeArea(.keyboard) // Compose has own keyboard handler
}
}
diff --git a/iosApp/iosApp/iOSApp.swift b/iosApp/iosApp/iOSApp.swift
index b7bf2f4..746155c 100644
--- a/iosApp/iosApp/iOSApp.swift
+++ b/iosApp/iosApp/iOSApp.swift
@@ -1,10 +1,26 @@
import SwiftUI
+import ComposeApp
+
@main
struct iOSApp: App {
- var body: some Scene {
- WindowGroup {
- ContentView()
- }
- }
+ private var lifecycle = LifecycleRegistryKt.LifecycleRegistry()
+
+ var body: some Scene {
+ WindowGroup {
+ GeometryReader { geo in
+ ContentView(
+ lifecycle:lifecycle,
+ topSafeArea: Float(geo.safeAreaInsets.top),
+ bottomSafeArea: Float(geo.safeAreaInsets.bottom)
+ )
+ .ignoresSafeArea()
+ .onTapGesture {
+ // Hide keyboard on tap outside of TextField
+ UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
+ }
+ }
+
+ }
+ }
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index a395d1f..968cc8d 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -1,49 +1,25 @@
-rootProject.name = "MyApplication"
-
-include(":androidApp")
-include(":shared")
+rootProject.name = "DecomposeApp"
+enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
pluginManagement {
repositories {
+ maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
+ google()
gradlePluginPortal()
mavenCentral()
- google()
- maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven { url = uri("https://jitpack.io") }
+ mavenLocal()
}
-
- plugins {
- val kotlinVersion = extra["kotlin.version"] as String
- val agpVersion = extra["agp.version"] as String
- val composeVersion = extra["compose.version"] as String
-
- kotlin("jvm").version(kotlinVersion)
- kotlin("multiplatform").version(kotlinVersion)
- kotlin("android").version(kotlinVersion)
-
- id("com.android.application").version(agpVersion)
- id("com.android.library").version(agpVersion)
-
- id("org.jetbrains.compose").version(composeVersion)
- }
-}
-
-plugins {
- id("org.gradle.toolchains.foojay-resolver-convention") version("0.7.0")
}
dependencyResolutionManagement {
repositories {
- mavenCentral()
google()
- gradlePluginPortal()
- mavenLocal()
+ mavenCentral()
maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
maven { url = uri("https://jitpack.io") }
- }
- versionCatalogs {
- create("deps") {
- from(files("deps.versions.toml"))
- }
+ mavenLocal()
}
}
+
+include(":composeApp")
\ No newline at end of file