├── shared ├── src │ ├── commonMain │ │ └── kotlin │ │ │ ├── Constants.kt │ │ │ ├── Platform.kt │ │ │ └── Greeting.kt │ ├── jvmMain │ │ └── kotlin │ │ │ └── Platform.jvm.kt │ ├── androidMain │ │ └── kotlin │ │ │ └── Platform.android.kt │ └── iosMain │ │ └── kotlin │ │ └── Platform.ios.kt └── build.gradle.kts ├── .kotlin └── metadata │ ├── kotlinTransformedCInteropMetadataLibraries │ ├── .shared-iosMain.cinteropLibraries │ ├── .shared-iosTest.cinteropLibraries │ ├── .shared-appleMain.cinteropLibraries │ ├── .shared-appleTest.cinteropLibraries │ ├── .shared-nativeMain.cinteropLibraries │ ├── .shared-nativeTest.cinteropLibraries │ ├── io.ktor-ktor-utils-2.3.11-iosMain-cinterop │ │ └── io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib │ ├── io.ktor-ktor-utils-2.3.12-iosMain-cinterop │ │ └── io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib │ ├── org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop │ │ └── org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib │ ├── org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop │ │ └── org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib │ ├── .composeApp-appleMain.cinteropLibraries │ ├── .composeApp-appleTest.cinteropLibraries │ ├── .composeApp-iosMain.cinteropLibraries │ ├── .composeApp-iosTest.cinteropLibraries │ ├── .composeApp-nativeMain.cinteropLibraries │ └── .composeApp-nativeTest.cinteropLibraries │ └── kotlinTransformedMetadataLibraries │ ├── io.ktor-ktor-io-2.3.11-posixMain-VFYQnA.klib │ ├── io.ktor-ktor-io-2.3.12-posixMain-3YsjwQ.klib │ ├── io.ktor-ktor-http-2.3.11-commonMain-QgEQ0Q.klib │ ├── io.ktor-ktor-http-2.3.11-posixMain-QgEQ0Q.klib │ ├── io.ktor-ktor-http-2.3.12-commonMain-W5sIeA.klib │ ├── io.ktor-ktor-http-2.3.12-posixMain-W5sIeA.klib │ ├── io.ktor-ktor-io-2.3.11-commonMain-VFYQnA.klib │ ├── io.ktor-ktor-io-2.3.11-darwinMain-sbySvA.klib │ ├── io.ktor-ktor-io-2.3.12-commonMain-3YsjwQ.klib │ ├── io.ktor-ktor-io-2.3.12-darwinMain-sbySvA.klib │ ├── io.ktor-ktor-utils-2.3.11-nixMain-kEcFvw.klib │ ├── io.ktor-ktor-utils-2.3.11-posixMain-kEcFvw.klib │ ├── io.ktor-ktor-utils-2.3.12-nixMain-kEcFvw.klib │ ├── io.ktor-ktor-utils-2.3.12-posixMain-kEcFvw.klib │ ├── com.squareup.okio-okio-3.9.0-unixMain-DWVyIA.klib │ ├── com.squareup.okio-okio-3.9.0-zlibMain-DWVyIA.klib │ ├── io.ktor-ktor-events-2.3.11-commonMain-_htHDg.klib │ ├── io.ktor-ktor-events-2.3.12-commonMain-Q6-xkw.klib │ ├── io.ktor-ktor-utils-2.3.11-commonMain-kEcFvw.klib │ ├── io.ktor-ktor-utils-2.3.11-darwinMain-TE4abA.klib │ ├── io.ktor-ktor-utils-2.3.12-commonMain-kEcFvw.klib │ ├── io.ktor-ktor-utils-2.3.12-darwinMain-TE4abA.klib │ ├── com.squareup.okio-okio-3.9.0-appleMain-BlIr1w.klib │ ├── com.squareup.okio-okio-3.9.0-commonMain-DWVyIA.klib │ ├── com.squareup.okio-okio-3.9.0-nativeMain-DWVyIA.klib │ ├── com.squareup.okio-okio-3.9.0-nonJvmMain-DWVyIA.klib │ ├── io.ktor-ktor-websockets-2.3.11-posixMain-8-9-_g.klib │ ├── io.ktor-ktor-websockets-2.3.12-posixMain-8-9-_g.klib │ ├── media.kamel-kamel-core-0.9.5-appleMain-aK6ixA.klib │ ├── media.kamel-kamel-core-0.9.5-commonMain-WfPfow.klib │ ├── media.kamel-kamel-image-0.9.5-appleMain-fGtM2w.klib │ ├── media.kamel-kamel-image-0.9.5-commonMain-oIJf-w.klib │ ├── media.kamel-kamel-image-0.9.5-nonJvmMain-oIJf-w.klib │ ├── org.jetbrains.skiko-skiko-0.8.4-iosMain-1T2ZCw.klib │ ├── com.squareup.okio-okio-3.9.0-hashFunctions-DWVyIA.klib │ ├── io.ktor-ktor-client-core-2.3.11-commonMain-FU-9lg.klib │ ├── io.ktor-ktor-client-core-2.3.11-posixMain-FU-9lg.klib │ ├── io.ktor-ktor-client-core-2.3.12-commonMain-FU-9lg.klib │ ├── io.ktor-ktor-client-core-2.3.12-posixMain-FU-9lg.klib │ ├── io.ktor-ktor-websockets-2.3.11-commonMain-8-9-_g.klib │ ├── io.ktor-ktor-websockets-2.3.12-commonMain-8-9-_g.klib │ ├── org.jetbrains.skiko-skiko-0.8.4-commonMain-DbI_Jg.klib │ ├── org.jetbrains.skiko-skiko-0.8.4-darwinMain-1T2ZCw.klib │ ├── org.jetbrains.skiko-skiko-0.8.4-nativeMain-DbI_Jg.klib │ ├── co.touchlab-stately-common-2.0.6-commonMain-WJbBBA.klib │ ├── co.touchlab-stately-isolate-2.0.6-commonMain-4Bzzzg.klib │ ├── co.touchlab-stately-strict-2.0.6-commonMain-0yIOhQ.klib │ ├── io.ktor-ktor-client-darwin-2.3.11-darwinMain-CnRCQQ.klib │ ├── io.ktor-ktor-client-darwin-2.3.12-darwinMain-CnRCQQ.klib │ ├── io.ktor-ktor-serialization-2.3.11-commonMain-NxrIfg.klib │ ├── io.ktor-ktor-serialization-2.3.12-commonMain-NxrIfg.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-commonMain-OrzU9w.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-darwinMain-OEwx0A.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-nativeMain-OEwx0A.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-skikoMain-OrzU9w.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-uikitMain-OEwx0A.klib │ ├── org.jetbrains.skiko-skiko-0.8.4-nativeJsMain-DbI_Jg.klib │ ├── androidx.annotation-annotation-1.8.0-commonMain-PJXh8Q.klib │ ├── androidx.annotation-annotation-1.8.0-nonJvmMain-PJXh8Q.klib │ ├── org.jetbrains.compose.ui-ui-1.6.11-jsNativeMain-OrzU9w.klib │ ├── org.jetbrains.compose.ui-ui-unit-1.6.11-jbMain-vwDMdg.klib │ ├── co.touchlab-stately-common-2.0.6-nativeCommonMain-WJbBBA.klib │ ├── co.touchlab-stately-concurrency-2.0.6-commonMain-CAw19g.klib │ ├── co.touchlab-stately-concurrency-2.0.6-darwinMain-oJtMMg.klib │ ├── co.touchlab-stately-isolate-2.0.6-nativeCommonMain-4Bzzzg.klib │ ├── co.touchlab-stately-strict-2.0.6-nativeCommonMain-0yIOhQ.klib │ ├── com.squareup.okio-okio-3.9.0-systemFileSystemMain-DWVyIA.klib │ ├── io.github.pdvrieze.xmlutil-core-0.86.3-commonMain-nC7WJg.klib │ ├── io.github.pdvrieze.xmlutil-core-0.86.3-nativeMain-nC7WJg.klib │ ├── org.jetbrains.compose.ui-ui-text-1.6.11-commonMain-aUvkxg.klib │ ├── org.jetbrains.compose.ui-ui-text-1.6.11-darwinMain-DK5x5Q.klib │ ├── org.jetbrains.compose.ui-ui-text-1.6.11-nativeMain-DK5x5Q.klib │ ├── org.jetbrains.compose.ui-ui-text-1.6.11-skikoMain-aUvkxg.klib │ ├── org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-oguluQ.klib │ ├── org.jetbrains.compose.ui-ui-unit-1.6.11-commonMain-vwDMdg.klib │ ├── org.jetbrains.compose.ui-ui-util-1.6.11-commonMain-LLOBPg.klib │ ├── org.jetbrains.compose.ui-ui-util-1.6.11-uikitMain-4Hpl6Q.klib │ ├── org.jetbrains.kotlinx-atomicfu-0.23.2-commonMain-yBS35w.klib │ ├── org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-yBS35w.klib │ ├── co.touchlab-stately-iso-collections-2.0.6-commonMain-dUgCfw.klib │ ├── io.github.pdvrieze.xmlutil-core-0.86.3-commonDomMain-nC7WJg.klib │ ├── org.jetbrains.compose.runtime-runtime-1.6.11-jbMain-CVJWAg.klib │ ├── org.jetbrains.compose.ui-ui-text-1.6.11-jsNativeMain-aUvkxg.klib │ ├── org.jetbrains.compose.ui-ui-unit-1.6.11-jsNativeMain-vwDMdg.klib │ ├── org.jetbrains.kotlin-kotlin-stdlib-2.0.0-commonMain-2bbUHA.klib │ ├── androidx.lifecycle-lifecycle-viewmodel-2.8.3-commonMain-vv0pmw.klib │ ├── androidx.lifecycle-lifecycle-viewmodel-2.8.3-darwinMain-4MgIRw.klib │ ├── androidx.lifecycle-lifecycle-viewmodel-2.8.3-nativeMain-vv0pmw.klib │ ├── androidx.lifecycle-lifecycle-viewmodel-2.8.3-nonJvmMain-vv0pmw.klib │ ├── co.touchlab-stately-concurrency-2.0.6-nativeCommonMain-CAw19g.klib │ ├── io.ktor-ktor-websocket-serialization-2.3.11-commonMain-8xBQEg.klib │ ├── io.ktor-ktor-websocket-serialization-2.3.12-commonMain-8xBQEg.klib │ ├── org.jetbrains.compose.runtime-runtime-1.6.11-commonMain-CVJWAg.klib │ ├── org.jetbrains.compose.runtime-runtime-1.6.11-nativeMain-CVJWAg.klib │ ├── org.jetbrains.compose.runtime-runtime-1.6.11-uikitMain-LSh9lw.klib │ ├── org.jetbrains.compose.ui-ui-geometry-1.6.11-commonMain-zDj2GQ.klib │ ├── org.jetbrains.compose.ui-ui-graphics-1.6.11-commonMain-jqr5iw.klib │ ├── org.jetbrains.compose.ui-ui-graphics-1.6.11-nativeMain-M9RlEw.klib │ ├── org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoMain-jqr5iw.klib │ ├── org.jetbrains.compose.material-material-1.6.11-commonMain-tGo7Ag.klib │ ├── org.jetbrains.compose.material-material-1.6.11-nativeMain-33WlwA.klib │ ├── org.jetbrains.compose.material-material-1.6.11-skikoMain-tGo7Ag.klib │ ├── org.jetbrains.compose.runtime-runtime-1.6.11-jsNativeMain-CVJWAg.klib │ ├── org.jetbrains.compose.ui-ui-graphics-1.6.11-jsNativeMain-jqr5iw.klib │ ├── io.github.pdvrieze.xmlutil-serialization-0.86.3-commonMain-6CN7gA.klib │ ├── io.github.pdvrieze.xmlutil-serialization-0.86.3-nativeMain-6CN7gA.klib │ ├── io.github.reactivecircus.cache4k-cache4k-0.13.0-commonMain-jqU5mQ.klib │ ├── io.github.reactivecircus.cache4k-cache4k-0.13.0-nonJvmMain-jqU5mQ.klib │ ├── org.jetbrains.compose.animation-animation-1.6.11-commonMain-5jNXZw.klib │ ├── org.jetbrains.compose.animation-animation-1.6.11-nativeMain-tpXTFg.klib │ ├── org.jetbrains.compose.animation-animation-core-1.6.11-jbMain-jNz1Aw.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-skikoMain-dXXsCQ.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-uikitMain-aASdXg.klib │ ├── org.jetbrains.compose.material-material-1.6.11-jsNativeMain-tGo7Ag.klib │ ├── org.jetbrains.kotlin-kotlin-test-2.0.0-annotationsCommonMain-24eTFQ.klib │ ├── org.jetbrains.kotlin-kotlin-test-2.0.0-assertionsCommonMain-24eTFQ.klib │ ├── org.jetbrains.compose.animation-animation-1.6.11-jsNativeMain-5jNXZw.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-commonMain-dXXsCQ.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-darwinMain-aASdXg.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-nativeMain-aASdXg.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-commonMain-UxhG-g.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeMain-UxhG-g.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-commonMain-XanZ2w.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeMain-XanZ2w.klib │ ├── org.jetbrains.compose.animation-animation-core-1.6.11-commonMain-jNz1Aw.klib │ ├── org.jetbrains.compose.animation-animation-core-1.6.11-uikitMain-2J6wbg.klib │ ├── org.jetbrains.compose.foundation-foundation-1.6.11-jsNativeMain-dXXsCQ.klib │ ├── org.jetbrains.compose.material-material-ripple-1.6.11-commonMain-8kHg7A.klib │ ├── org.jetbrains.compose.material-material-ripple-1.6.11-nativeMain-zsMeyQ.klib │ ├── org.jetbrains.compose.runtime-runtime-saveable-1.6.11-commonMain-pCPplQ.klib │ ├── org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoExcludingWebMain-jqr5iw.klib │ ├── org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-commonMain-oyg_tw.klib │ ├── org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-nativeMain-oyg_tw.klib │ ├── org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-commonMain-JDnEfA.klib │ ├── org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-nativeMain-JDnEfA.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-commonMain-_oGBew.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-nonJvmMain-_oGBew.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-commonMain-Cd-IGw.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nativeMain-Cd-IGw.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nonJvmMain-Cd-IGw.klib │ ├── org.jetbrains.compose.animation-animation-core-1.6.11-jsNativeMain-jNz1Aw.klib │ ├── org.jetbrains.compose.collection-internal-collection-1.6.11-jbMain-hcu3Ug.klib │ ├── org.jetbrains.compose.foundation-foundation-layout-1.6.11-skikoMain-89e7lw.klib │ ├── org.jetbrains.compose.foundation-foundation-layout-1.6.11-uikitMain-BKR0pA.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-concurrentMain-UxhG-g.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-concurrentMain-XanZ2w.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-commonMain-ydSu5Q.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nativeMain-ydSu5Q.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nonJvmMain-ydSu5Q.klib │ ├── org.jetbrains.compose.annotation-internal-annotation-1.6.11-commonMain-cNNKSA.klib │ ├── org.jetbrains.compose.annotation-internal-annotation-1.6.11-nonJvmMain-cNNKSA.klib │ ├── org.jetbrains.compose.collection-internal-collection-1.6.11-commonMain-hcu3Ug.klib │ ├── org.jetbrains.compose.components-components-resources-1.6.11-iosMain-mlvQUA.klib │ ├── org.jetbrains.compose.components-components-resources-1.6.11-skikoMain-44UCqg.klib │ ├── org.jetbrains.compose.foundation-foundation-layout-1.6.11-commonMain-89e7lw.klib │ ├── org.jetbrains.compose.foundation-foundation-layout-1.6.11-jsNativeMain-89e7lw.klib │ ├── org.jetbrains.compose.material-material-icons-core-1.6.11-commonMain-XjyzjQ.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeDarwinMain-sy5nKg.klib │ ├── org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeDarwinMain-sy5nKg.klib │ ├── org.jetbrains.compose.collection-internal-collection-1.6.11-jsNativeMain-hcu3Ug.klib │ ├── org.jetbrains.compose.components-components-resources-1.6.11-commonMain-44UCqg.klib │ ├── org.jetbrains.compose.components-components-resources-1.6.11-nativeMain-mlvQUA.klib │ ├── org.jetbrains.androidx.lifecycle-lifecycle-runtime-compose-2.8.0-commonMain-mvP4Vw.klib │ ├── org.jetbrains.compose.components-components-resources-1.6.11-blockingMain-44UCqg.klib │ └── org.jetbrains.compose.components-components-ui-tooling-preview-1.6.11-commonMain--i3iSw.klib ├── iosApp ├── Configuration │ └── Config.xcconfig ├── iosApp │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AppIcon.appiconset │ │ │ ├── app-icon-1024.png │ │ │ └── Contents.json │ │ └── AccentColor.colorset │ │ │ └── Contents.json │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── iOSApp.swift │ ├── ContentView.swift │ └── Info.plist └── iosApp.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── ahmedadelismail.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ └── ahmedadelismail.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── composeApp ├── src │ ├── androidMain │ │ ├── res │ │ │ ├── values │ │ │ │ └── strings.xml │ │ │ ├── mipmap-hdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-mdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-xxxhdpi │ │ │ │ ├── ic_launcher.png │ │ │ │ └── ic_launcher_round.png │ │ │ ├── mipmap-anydpi-v26 │ │ │ │ ├── ic_launcher.xml │ │ │ │ └── ic_launcher_round.xml │ │ │ ├── drawable-v24 │ │ │ │ └── ic_launcher_foreground.xml │ │ │ └── drawable │ │ │ │ └── ic_launcher_background.xml │ │ ├── kotlin │ │ │ └── com │ │ │ │ └── aismail │ │ │ │ └── project │ │ │ │ └── MainActivity.kt │ │ └── AndroidManifest.xml │ ├── commonMain │ │ ├── kotlin │ │ │ ├── shared │ │ │ │ └── adapters │ │ │ │ │ ├── Clearable.kt │ │ │ │ │ └── StateHolder.kt │ │ │ ├── login │ │ │ │ ├── core │ │ │ │ │ ├── User.kt │ │ │ │ │ ├── ports │ │ │ │ │ │ ├── LoginDataSourcePort.kt │ │ │ │ │ │ └── LoginStatePort.kt │ │ │ │ │ └── scenarios │ │ │ │ │ │ └── LoginBusinessLogic.kt │ │ │ │ ├── adapters │ │ │ │ │ ├── Mapping.kt │ │ │ │ │ ├── LoginState.kt │ │ │ │ │ └── LoginDataSource.kt │ │ │ │ └── ui │ │ │ │ │ └── LoginScreen.kt │ │ │ ├── navigation │ │ │ │ ├── core │ │ │ │ │ ├── ports │ │ │ │ │ │ ├── NavigationDataSourcePort.kt │ │ │ │ │ │ └── NavigationStatePort.kt │ │ │ │ │ ├── Screens.kt │ │ │ │ │ └── NavigationBusinessLogic.kt │ │ │ │ ├── adapters │ │ │ │ │ ├── NavigationDataSources.kt │ │ │ │ │ └── NavigationState.kt │ │ │ │ └── BackHandling.kt │ │ │ ├── data │ │ │ │ ├── models │ │ │ │ │ ├── AllGithubRepositoriesData.kt │ │ │ │ │ ├── OwnerData.kt │ │ │ │ │ ├── UserData.kt │ │ │ │ │ └── GithubRepositoryData.kt │ │ │ │ ├── InMemoryCache.kt │ │ │ │ ├── DataSources.kt │ │ │ │ ├── DataSourcesImpl.kt │ │ │ │ └── mocks │ │ │ │ │ └── MockServerResponse.kt │ │ │ ├── favorites │ │ │ │ ├── core │ │ │ │ │ ├── ports │ │ │ │ │ │ ├── AllFavoritesDataSourcesPort.kt │ │ │ │ │ │ ├── FavoriteDataSourcesPort.kt │ │ │ │ │ │ ├── AllFavoritesStatePort.kt │ │ │ │ │ │ └── FavoriteStatePort.kt │ │ │ │ │ ├── entities │ │ │ │ │ │ └── FavoriteRepository.kt │ │ │ │ │ └── scenarios │ │ │ │ │ │ ├── FavoritesBusinessLogic.kt │ │ │ │ │ │ └── AllFavoritesBusinessLogic.kt │ │ │ │ ├── adapters │ │ │ │ │ ├── AllFavoritesDataSources.kt │ │ │ │ │ ├── FavoriteDataSources.kt │ │ │ │ │ ├── Mapping.kt │ │ │ │ │ ├── FavoriteState.kt │ │ │ │ │ └── AllFavoritesState.kt │ │ │ │ └── ui │ │ │ │ │ └── FavoritesScreen.kt │ │ │ ├── home │ │ │ │ ├── core │ │ │ │ │ ├── ports │ │ │ │ │ │ ├── HomeStatePort.kt │ │ │ │ │ │ ├── HomeDataSourcesPort.kt │ │ │ │ │ │ ├── GithubRepositoryDataSourcesPort.kt │ │ │ │ │ │ └── GithubRepositoryStatePort.kt │ │ │ │ │ ├── entities │ │ │ │ │ │ └── GithubRepository.kt │ │ │ │ │ └── scenarios │ │ │ │ │ │ ├── GithubRepositoryBusinessLogic.kt │ │ │ │ │ │ └── HomeBusinessLogic.kt │ │ │ │ ├── adapters │ │ │ │ │ ├── Mapping.kt │ │ │ │ │ ├── HomeDataSources.kt │ │ │ │ │ ├── HomeState.kt │ │ │ │ │ ├── GithubRepositoryDataSources.kt │ │ │ │ │ └── GithubRepositoryState.kt │ │ │ │ └── ui │ │ │ │ │ └── HomeScreen.kt │ │ │ ├── splash │ │ │ │ └── SplashScreen.kt │ │ │ └── App.kt │ │ └── composeResources │ │ │ └── drawable │ │ │ └── compose-multiplatform.xml │ ├── iosMain │ │ └── kotlin │ │ │ └── MainViewController.kt │ └── desktopMain │ │ └── kotlin │ │ └── main.kt └── build.gradle.kts ├── gradle ├── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties └── libs.versions.toml ├── gradle.properties ├── server ├── src │ └── main │ │ ├── resources │ │ └── logback.xml │ │ └── kotlin │ │ └── com │ │ └── aismail │ │ └── project │ │ └── Application.kt └── build.gradle.kts ├── .gitignore ├── settings.gradle.kts ├── README.md ├── gradlew.bat └── gradlew /shared/src/commonMain/kotlin/Constants.kt: -------------------------------------------------------------------------------- 1 | const val SERVER_PORT = 8080 -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-iosMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-iosTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-appleMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-appleTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-nativeMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.shared-nativeTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /iosApp/Configuration/Config.xcconfig: -------------------------------------------------------------------------------- 1 | TEAM_ID= 2 | BUNDLE_ID=com.aismail.project.AIsmailProject 3 | APP_NAME=AIsmailProject -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | AIsmailProject 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/Platform.kt: -------------------------------------------------------------------------------- 1 | interface Platform { 2 | val name: String 3 | } 4 | 5 | expect fun getPlatform(): Platform -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/shared/adapters/Clearable.kt: -------------------------------------------------------------------------------- 1 | package shared.adapters 2 | 3 | interface Clearable { 4 | fun clear() 5 | } -------------------------------------------------------------------------------- /iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/core/User.kt: -------------------------------------------------------------------------------- 1 | package login.core 2 | 3 | data class User( 4 | val metadata: Any, 5 | val id: Long, 6 | val token: String, 7 | ) -------------------------------------------------------------------------------- /composeApp/src/iosMain/kotlin/MainViewController.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.ui.window.ComposeUIViewController 2 | 3 | fun MainViewController() = ComposeUIViewController { App() } -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/Greeting.kt: -------------------------------------------------------------------------------- 1 | class Greeting { 2 | private val platform = getPlatform() 3 | 4 | fun greet(): String { 5 | return "Hello, ${platform.name}!" 6 | } 7 | } -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/app-icon-1024.png -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/composeApp/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/core/ports/NavigationDataSourcePort.kt: -------------------------------------------------------------------------------- 1 | package navigation.core.ports 2 | 3 | interface NavigationDataSourcePort { 4 | suspend fun isLoggedIn(): Boolean 5 | } -------------------------------------------------------------------------------- /iosApp/iosApp/iOSApp.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | 3 | @main 4 | struct iOSApp: App { 5 | var body: some Scene { 6 | WindowGroup { 7 | ContentView() 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /shared/src/jvmMain/kotlin/Platform.jvm.kt: -------------------------------------------------------------------------------- 1 | class JVMPlatform: Platform { 2 | override val name: String = "Java ${System.getProperty("java.version")}" 3 | } 4 | 5 | actual fun getPlatform(): Platform = JVMPlatform() -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } -------------------------------------------------------------------------------- /shared/src/androidMain/kotlin/Platform.android.kt: -------------------------------------------------------------------------------- 1 | import android.os.Build 2 | 3 | class AndroidPlatform : Platform { 4 | override val name: String = "Android ${Build.VERSION.SDK_INT}" 5 | } 6 | 7 | actual fun getPlatform(): Platform = AndroidPlatform() -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-posixMain-VFYQnA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-posixMain-VFYQnA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-posixMain-3YsjwQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-posixMain-3YsjwQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.11-commonMain-QgEQ0Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.11-commonMain-QgEQ0Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.11-posixMain-QgEQ0Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.11-posixMain-QgEQ0Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.12-commonMain-W5sIeA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.12-commonMain-W5sIeA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.12-posixMain-W5sIeA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-http-2.3.12-posixMain-W5sIeA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-commonMain-VFYQnA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-commonMain-VFYQnA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-darwinMain-sbySvA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.11-darwinMain-sbySvA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-commonMain-3YsjwQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-commonMain-3YsjwQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-darwinMain-sbySvA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-io-2.3.12-darwinMain-sbySvA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-nixMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-nixMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-posixMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-posixMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-nixMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-nixMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-posixMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-posixMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-unixMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-unixMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-zlibMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-zlibMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-events-2.3.11-commonMain-_htHDg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-events-2.3.11-commonMain-_htHDg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-events-2.3.12-commonMain-Q6-xkw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-events-2.3.12-commonMain-Q6-xkw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-commonMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-commonMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-darwinMain-TE4abA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.11-darwinMain-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-commonMain-kEcFvw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-commonMain-kEcFvw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-darwinMain-TE4abA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-utils-2.3.12-darwinMain-TE4abA.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/core/Screens.kt: -------------------------------------------------------------------------------- 1 | package navigation.core 2 | 3 | sealed interface Screens { 4 | data object Splash : Screens 5 | data object Login : Screens 6 | data object Home : Screens 7 | data object Favorites : Screens 8 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-appleMain-BlIr1w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-appleMain-BlIr1w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-commonMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-commonMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-nativeMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-nativeMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-nonJvmMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-nonJvmMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.11-posixMain-8-9-_g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.11-posixMain-8-9-_g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.12-posixMain-8-9-_g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.12-posixMain-8-9-_g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-core-0.9.5-appleMain-aK6ixA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-core-0.9.5-appleMain-aK6ixA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-core-0.9.5-commonMain-WfPfow.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-core-0.9.5-commonMain-WfPfow.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-appleMain-fGtM2w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-appleMain-fGtM2w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-commonMain-oIJf-w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-commonMain-oIJf-w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-nonJvmMain-oIJf-w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/media.kamel-kamel-image-0.9.5-nonJvmMain-oIJf-w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-iosMain-1T2ZCw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-iosMain-1T2ZCw.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/models/AllGithubRepositoriesData.kt: -------------------------------------------------------------------------------- 1 | package data.models 2 | 3 | import GithubRepositoryData 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class AllGithubRepositoriesData(val data: List) -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-hashFunctions-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-hashFunctions-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.11-commonMain-FU-9lg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.11-commonMain-FU-9lg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.11-posixMain-FU-9lg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.11-posixMain-FU-9lg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.12-commonMain-FU-9lg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.12-commonMain-FU-9lg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.12-posixMain-FU-9lg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-core-2.3.12-posixMain-FU-9lg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.11-commonMain-8-9-_g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.11-commonMain-8-9-_g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.12-commonMain-8-9-_g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websockets-2.3.12-commonMain-8-9-_g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-commonMain-DbI_Jg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-commonMain-DbI_Jg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-darwinMain-1T2ZCw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-darwinMain-1T2ZCw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-nativeMain-DbI_Jg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-nativeMain-DbI_Jg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-common-2.0.6-commonMain-WJbBBA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-common-2.0.6-commonMain-WJbBBA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-isolate-2.0.6-commonMain-4Bzzzg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-isolate-2.0.6-commonMain-4Bzzzg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-strict-2.0.6-commonMain-0yIOhQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-strict-2.0.6-commonMain-0yIOhQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-darwin-2.3.11-darwinMain-CnRCQQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-darwin-2.3.11-darwinMain-CnRCQQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-darwin-2.3.12-darwinMain-CnRCQQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-client-darwin-2.3.12-darwinMain-CnRCQQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-serialization-2.3.11-commonMain-NxrIfg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-serialization-2.3.11-commonMain-NxrIfg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-serialization-2.3.12-commonMain-NxrIfg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-serialization-2.3.12-commonMain-NxrIfg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-commonMain-OrzU9w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-commonMain-OrzU9w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-darwinMain-OEwx0A.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-darwinMain-OEwx0A.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-nativeMain-OEwx0A.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-nativeMain-OEwx0A.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-skikoMain-OrzU9w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-skikoMain-OrzU9w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-uikitMain-OEwx0A.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-uikitMain-OEwx0A.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-nativeJsMain-DbI_Jg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.skiko-skiko-0.8.4-nativeJsMain-DbI_Jg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.annotation-annotation-1.8.0-commonMain-PJXh8Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.annotation-annotation-1.8.0-commonMain-PJXh8Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.annotation-annotation-1.8.0-nonJvmMain-PJXh8Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.annotation-annotation-1.8.0-nonJvmMain-PJXh8Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-jsNativeMain-OrzU9w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-1.6.11-jsNativeMain-OrzU9w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-jbMain-vwDMdg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-jbMain-vwDMdg.klib -------------------------------------------------------------------------------- /shared/src/iosMain/kotlin/Platform.ios.kt: -------------------------------------------------------------------------------- 1 | import platform.UIKit.UIDevice 2 | 3 | class IOSPlatform: Platform { 4 | override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion 5 | } 6 | 7 | actual fun getPlatform(): Platform = IOSPlatform() -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-common-2.0.6-nativeCommonMain-WJbBBA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-common-2.0.6-nativeCommonMain-WJbBBA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-commonMain-CAw19g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-commonMain-CAw19g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-darwinMain-oJtMMg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-darwinMain-oJtMMg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-isolate-2.0.6-nativeCommonMain-4Bzzzg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-isolate-2.0.6-nativeCommonMain-4Bzzzg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-strict-2.0.6-nativeCommonMain-0yIOhQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-strict-2.0.6-nativeCommonMain-0yIOhQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-systemFileSystemMain-DWVyIA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/com.squareup.okio-okio-3.9.0-systemFileSystemMain-DWVyIA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-commonMain-nC7WJg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-commonMain-nC7WJg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-nativeMain-nC7WJg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-nativeMain-nC7WJg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-commonMain-aUvkxg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-commonMain-aUvkxg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-darwinMain-DK5x5Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-darwinMain-DK5x5Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-nativeMain-DK5x5Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-nativeMain-DK5x5Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-skikoMain-aUvkxg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-skikoMain-aUvkxg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-oguluQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-oguluQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-commonMain-vwDMdg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-commonMain-vwDMdg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-util-1.6.11-commonMain-LLOBPg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-util-1.6.11-commonMain-LLOBPg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-util-1.6.11-uikitMain-4Hpl6Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-util-1.6.11-uikitMain-4Hpl6Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-commonMain-yBS35w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-commonMain-yBS35w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-yBS35w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-yBS35w.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/ports/AllFavoritesDataSourcesPort.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.ports 2 | 3 | import favorites.core.entities.FavoriteRepository 4 | 5 | interface AllFavoritesDataSourcesPort { 6 | suspend fun getAllFavorites(): List 7 | } 8 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/ports/FavoriteDataSourcesPort.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.ports 2 | 3 | import favorites.core.entities.FavoriteRepository 4 | 5 | interface FavoriteDataSourcesPort { 6 | suspend fun removeFromFavorites(favoriteRepository: FavoriteRepository) 7 | } -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/ahmedadelismail.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/iosApp/iosApp.xcodeproj/project.xcworkspace/xcuserdata/ahmedadelismail.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-iso-collections-2.0.6-commonMain-dUgCfw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-iso-collections-2.0.6-commonMain-dUgCfw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-commonDomMain-nC7WJg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-core-0.86.3-commonDomMain-nC7WJg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-jbMain-CVJWAg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-jbMain-CVJWAg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-jsNativeMain-aUvkxg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-text-1.6.11-jsNativeMain-aUvkxg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-jsNativeMain-vwDMdg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-unit-1.6.11-jsNativeMain-vwDMdg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-stdlib-2.0.0-commonMain-2bbUHA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-stdlib-2.0.0-commonMain-2bbUHA.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/ports/HomeStatePort.kt: -------------------------------------------------------------------------------- 1 | package home.core.ports 2 | 3 | interface HomeStatePort { 4 | val dataSourcePort: HomeDataSourcesPort 5 | var progress: Boolean 6 | val repositories: MutableList 7 | var error: Throwable? 8 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/core/NavigationBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package navigation.core 2 | 3 | import navigation.core.ports.NavigationStatePort 4 | 5 | suspend fun NavigationStatePort.initialize() { 6 | screen = if (dataSourcePort.isLoggedIn()) Screens.Home else Screens.Login 7 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-commonMain-vv0pmw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-commonMain-vv0pmw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-darwinMain-4MgIRw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-darwinMain-4MgIRw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-nativeMain-vv0pmw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-nativeMain-vv0pmw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-nonJvmMain-vv0pmw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/androidx.lifecycle-lifecycle-viewmodel-2.8.3-nonJvmMain-vv0pmw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-nativeCommonMain-CAw19g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/co.touchlab-stately-concurrency-2.0.6-nativeCommonMain-CAw19g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websocket-serialization-2.3.11-commonMain-8xBQEg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websocket-serialization-2.3.11-commonMain-8xBQEg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websocket-serialization-2.3.12-commonMain-8xBQEg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.ktor-ktor-websocket-serialization-2.3.12-commonMain-8xBQEg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-commonMain-CVJWAg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-commonMain-CVJWAg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-nativeMain-CVJWAg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-nativeMain-CVJWAg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-uikitMain-LSh9lw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-uikitMain-LSh9lw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-geometry-1.6.11-commonMain-zDj2GQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-geometry-1.6.11-commonMain-zDj2GQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-commonMain-jqr5iw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-commonMain-jqr5iw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-nativeMain-M9RlEw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-nativeMain-M9RlEw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoMain-jqr5iw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoMain-jqr5iw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-commonMain-tGo7Ag.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-commonMain-tGo7Ag.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-nativeMain-33WlwA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-nativeMain-33WlwA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-skikoMain-tGo7Ag.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-skikoMain-tGo7Ag.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-jsNativeMain-CVJWAg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-1.6.11-jsNativeMain-CVJWAg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-jsNativeMain-jqr5iw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-jsNativeMain-jqr5iw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-serialization-0.86.3-commonMain-6CN7gA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-serialization-0.86.3-commonMain-6CN7gA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-serialization-0.86.3-nativeMain-6CN7gA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.pdvrieze.xmlutil-serialization-0.86.3-nativeMain-6CN7gA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.reactivecircus.cache4k-cache4k-0.13.0-commonMain-jqU5mQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.reactivecircus.cache4k-cache4k-0.13.0-commonMain-jqU5mQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.reactivecircus.cache4k-cache4k-0.13.0-nonJvmMain-jqU5mQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/io.github.reactivecircus.cache4k-cache4k-0.13.0-nonJvmMain-jqU5mQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-commonMain-5jNXZw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-commonMain-5jNXZw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-nativeMain-tpXTFg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-nativeMain-tpXTFg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-jbMain-jNz1Aw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-jbMain-jNz1Aw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-skikoMain-dXXsCQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-skikoMain-dXXsCQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-uikitMain-aASdXg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-uikitMain-aASdXg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-jsNativeMain-tGo7Ag.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-1.6.11-jsNativeMain-tGo7Ag.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.0.0-annotationsCommonMain-24eTFQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.0.0-annotationsCommonMain-24eTFQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.0.0-assertionsCommonMain-24eTFQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlin-kotlin-test-2.0.0-assertionsCommonMain-24eTFQ.klib -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-jsNativeMain-5jNXZw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-1.6.11-jsNativeMain-5jNXZw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-commonMain-dXXsCQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-commonMain-dXXsCQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-darwinMain-aASdXg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-darwinMain-aASdXg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-nativeMain-aASdXg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-nativeMain-aASdXg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-commonMain-UxhG-g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-commonMain-UxhG-g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeMain-UxhG-g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeMain-UxhG-g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-commonMain-XanZ2w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-commonMain-XanZ2w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeMain-XanZ2w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeMain-XanZ2w.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/ports/AllFavoritesStatePort.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.ports 2 | 3 | interface AllFavoritesStatePort { 4 | val dataSources: AllFavoritesDataSourcesPort 5 | val favorites: MutableList 6 | var progress: Boolean 7 | var error: Throwable? 8 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/ports/HomeDataSourcesPort.kt: -------------------------------------------------------------------------------- 1 | package home.core.ports 2 | 3 | import home.core.entities.GithubRepository 4 | 5 | interface HomeDataSourcesPort { 6 | suspend fun getAllRepositories(): List 7 | suspend fun getAllFavorites(): List 8 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-commonMain-jNz1Aw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-commonMain-jNz1Aw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-uikitMain-2J6wbg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-uikitMain-2J6wbg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-jsNativeMain-dXXsCQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-1.6.11-jsNativeMain-dXXsCQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-ripple-1.6.11-commonMain-8kHg7A.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-ripple-1.6.11-commonMain-8kHg7A.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-ripple-1.6.11-nativeMain-zsMeyQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-ripple-1.6.11-nativeMain-zsMeyQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-saveable-1.6.11-commonMain-pCPplQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.runtime-runtime-saveable-1.6.11-commonMain-pCPplQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoExcludingWebMain-jqr5iw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.ui-ui-graphics-1.6.11-skikoExcludingWebMain-jqr5iw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-commonMain-oyg_tw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-commonMain-oyg_tw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-nativeMain-oyg_tw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-core-1.6.3-nativeMain-oyg_tw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-commonMain-JDnEfA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-commonMain-JDnEfA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-nativeMain-JDnEfA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-serialization-json-1.6.3-nativeMain-JDnEfA.klib -------------------------------------------------------------------------------- /composeApp/src/desktopMain/kotlin/main.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.ui.window.Window 2 | import androidx.compose.ui.window.application 3 | 4 | fun main() = application { 5 | Window( 6 | onCloseRequest = ::exitApplication, 7 | title = "AIsmailProject", 8 | ) { 9 | App() 10 | } 11 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-commonMain-_oGBew.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-commonMain-_oGBew.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-nonJvmMain-_oGBew.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-common-2.8.0-nonJvmMain-_oGBew.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-commonMain-Cd-IGw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-commonMain-Cd-IGw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nativeMain-Cd-IGw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nativeMain-Cd-IGw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nonJvmMain-Cd-IGw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-2.8.0-nonJvmMain-Cd-IGw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-jsNativeMain-jNz1Aw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.animation-animation-core-1.6.11-jsNativeMain-jNz1Aw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-jbMain-hcu3Ug.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-jbMain-hcu3Ug.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-skikoMain-89e7lw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-skikoMain-89e7lw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-uikitMain-BKR0pA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-uikitMain-BKR0pA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-concurrentMain-UxhG-g.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-concurrentMain-UxhG-g.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-concurrentMain-XanZ2w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-concurrentMain-XanZ2w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-commonMain-ydSu5Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-commonMain-ydSu5Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nativeMain-ydSu5Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nativeMain-ydSu5Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nonJvmMain-ydSu5Q.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-viewmodel-2.8.0-nonJvmMain-ydSu5Q.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.annotation-internal-annotation-1.6.11-commonMain-cNNKSA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.annotation-internal-annotation-1.6.11-commonMain-cNNKSA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.annotation-internal-annotation-1.6.11-nonJvmMain-cNNKSA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.annotation-internal-annotation-1.6.11-nonJvmMain-cNNKSA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-commonMain-hcu3Ug.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-commonMain-hcu3Ug.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-iosMain-mlvQUA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-iosMain-mlvQUA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-skikoMain-44UCqg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-skikoMain-44UCqg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-commonMain-89e7lw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-commonMain-89e7lw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-jsNativeMain-89e7lw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.foundation-foundation-layout-1.6.11-jsNativeMain-89e7lw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-icons-core-1.6.11-commonMain-XjyzjQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.material-material-icons-core-1.6.11-commonMain-XjyzjQ.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeDarwinMain-sy5nKg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.0-nativeDarwinMain-sy5nKg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeDarwinMain-sy5nKg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.kotlinx-kotlinx-coroutines-core-1.8.1-nativeDarwinMain-sy5nKg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-jsNativeMain-hcu3Ug.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.collection-internal-collection-1.6.11-jsNativeMain-hcu3Ug.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-commonMain-44UCqg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-commonMain-44UCqg.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-nativeMain-mlvQUA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-nativeMain-mlvQUA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-compose-2.8.0-commonMain-mvP4Vw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.androidx.lifecycle-lifecycle-runtime-compose-2.8.0-commonMain-mvP4Vw.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-blockingMain-44UCqg.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-resources-1.6.11-blockingMain-44UCqg.klib -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/ports/GithubRepositoryDataSourcesPort.kt: -------------------------------------------------------------------------------- 1 | package home.core.ports 2 | 3 | import home.core.entities.GithubRepository 4 | 5 | interface GithubRepositoryDataSourcesPort { 6 | suspend fun addToFavorites(repository: GithubRepository) 7 | suspend fun removeFromFavorites(repository: GithubRepository) 8 | } -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "app-icon-1024.png", 5 | "idiom" : "universal", 6 | "platform" : "ios", 7 | "size" : "1024x1024" 8 | } 9 | ], 10 | "info" : { 11 | "author" : "xcode", 12 | "version" : 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-ui-tooling-preview-1.6.11-commonMain--i3iSw.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedMetadataLibraries/org.jetbrains.compose.components-components-ui-tooling-preview-1.6.11-commonMain--i3iSw.klib -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/core/ports/NavigationStatePort.kt: -------------------------------------------------------------------------------- 1 | package navigation.core.ports 2 | 3 | import navigation.core.Screens 4 | import shared.adapters.StateHolder 5 | 6 | interface NavigationStatePort { 7 | val dataSourcePort: NavigationDataSourcePort 8 | var screen: Screens 9 | var state: StateHolder<*>? 10 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/entities/FavoriteRepository.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.entities 2 | 3 | data class FavoriteRepository( 4 | val metadata: Any, 5 | val id: Long, 6 | val name: String? = null, 7 | val ownerName: String? = null, 8 | val avatarUrl: String? = null, 9 | val stargazersCount: Int? = null, 10 | ) -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.11-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.11-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/ports/FavoriteStatePort.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.ports 2 | 3 | import favorites.core.entities.FavoriteRepository 4 | 5 | interface FavoriteStatePort { 6 | val dataSources: FavoriteDataSourcesPort 7 | val favoriteRepository: FavoriteRepository 8 | var progress: Boolean 9 | var error: Throwable? 10 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | 3 | #Gradle 4 | org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M" 5 | 6 | #Android 7 | android.nonTransitiveRClass=true 8 | android.useAndroidX=true 9 | 10 | #Kotlin Multiplatform 11 | kotlin.mpp.enableCInteropCommonization=true 12 | 13 | #Ktor 14 | io.ktor.development=true -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/scenarios/FavoritesBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.scenarios 2 | 3 | import favorites.core.ports.FavoriteStatePort 4 | 5 | suspend fun FavoriteStatePort.removeFromFavorite() { 6 | progress = true 7 | runCatching { dataSources.removeFromFavorites(favoriteRepository) } 8 | .onFailure { error = it } 9 | progress = false 10 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/ports/GithubRepositoryStatePort.kt: -------------------------------------------------------------------------------- 1 | package home.core.ports 2 | 3 | import home.core.entities.GithubRepository 4 | 5 | interface GithubRepositoryStatePort { 6 | val dataSourcePort: GithubRepositoryDataSourcesPort 7 | val repository: GithubRepository 8 | var isFavorite: Boolean 9 | var progress: Boolean 10 | var error: Throwable? 11 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ahmed-Adel-Ismail/KMM-Compose-2024/HEAD/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/models/OwnerData.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.serialization.SerialName 2 | import kotlinx.serialization.Serializable 3 | 4 | @Serializable 5 | data class OwnerData( 6 | @SerialName("id") val id: Long? = null, 7 | @SerialName("private") val isPrivate: Boolean? = null, 8 | @SerialName("name") val name: String? = null, 9 | @SerialName("avatar_url") val avatarUrl: String? = null 10 | ) -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/core/ports/LoginDataSourcePort.kt: -------------------------------------------------------------------------------- 1 | package login.core.ports 2 | 3 | import login.core.User 4 | 5 | interface LoginDataSourcePort { 6 | suspend fun getUsernameValidation(): List<(String?) -> Boolean> 7 | suspend fun getPasswordValidations(): List<(String?) -> Boolean> 8 | suspend fun login(username: String?, password: String?): User 9 | suspend fun saveUser(user: User) 10 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/adapters/NavigationDataSources.kt: -------------------------------------------------------------------------------- 1 | package navigation.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import navigation.core.ports.NavigationDataSourcePort 6 | 7 | class NavigationDataSources( 8 | private val dataSources: DataSources = DataSourcesImpl 9 | ) : NavigationDataSourcePort { 10 | override suspend fun isLoggedIn(): Boolean = dataSources.isLoggedIn() 11 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/core/ports/LoginStatePort.kt: -------------------------------------------------------------------------------- 1 | package login.core.ports 2 | 3 | interface LoginStatePort { 4 | val dataSourcePort: LoginDataSourcePort 5 | var progress: Boolean 6 | var userName: String? 7 | var password: String? 8 | var result: Result? 9 | 10 | sealed interface Result { 11 | data object Success : Result 12 | data class Error(val error: Throwable) : Result 13 | } 14 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/adapters/Mapping.kt: -------------------------------------------------------------------------------- 1 | package login.adapters 2 | 3 | import data.models.UserData 4 | import login.core.User 5 | 6 | fun createUser(userData: UserData) = User( 7 | metadata = userData, 8 | id = userData.id ?: throw IllegalArgumentException("User id is required"), 9 | token = userData.token ?: throw IllegalArgumentException("User token is required"), 10 | ) 11 | 12 | val User.userData: UserData 13 | get() = metadata as UserData -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/shared/adapters/StateHolder.kt: -------------------------------------------------------------------------------- 1 | package shared.adapters 2 | 3 | import data.cache 4 | 5 | class StateHolder(val name: String, private val initialState: T) : Clearable { 6 | private var state by cache(name) 7 | 8 | fun state(): T = state ?: initialState.also { state = it } 9 | 10 | override fun clear() { 11 | val finalState = state 12 | if (finalState is Clearable) finalState.clear() 13 | state = null 14 | } 15 | } -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/xcuserdata/ahmedadelismail.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iosApp.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/models/UserData.kt: -------------------------------------------------------------------------------- 1 | package data.models 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | @Serializable 7 | data class UserData( 8 | @SerialName("id") val id: Long? = null, 9 | @SerialName("token") val token: String? = null, 10 | @SerialName("name") val name: String? = null, 11 | @SerialName("email") val email: String? = null, 12 | @SerialName("avatar_url") val avatarUrl: String? = null, 13 | ) -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/entities/GithubRepository.kt: -------------------------------------------------------------------------------- 1 | package home.core.entities 2 | 3 | data class GithubRepository( 4 | /** 5 | * holds the pojo received from data source to be used later on when 6 | * dealing with data sources layer in other operations 7 | */ 8 | val metadata: Any, 9 | val id: Long, 10 | val name: String? = null, 11 | val ownerName: String? = null, 12 | val avatarUrl: String? = null, 13 | val stargazersCount: Int? = null, 14 | ) -------------------------------------------------------------------------------- /server/src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/BackHandling.kt: -------------------------------------------------------------------------------- 1 | package navigation 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateOf 5 | import androidx.compose.runtime.setValue 6 | import kotlin.properties.Delegates 7 | 8 | class Provider(val value: T) {} 9 | 10 | class OnBackPressedChannel { 11 | var isBackPressActive by mutableStateOf(false) 12 | var onBackPressed: (() -> Unit)? by Delegates.observable(null) { _, _, value -> 13 | isBackPressActive = value != null 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Gradle files 2 | .gradle/ 3 | build/ 4 | 5 | # Local configuration file (sdk path, etc) 6 | local.properties 7 | 8 | # Log/OS Files 9 | *.log 10 | 11 | # Android Studio generated files and folders 12 | captures/ 13 | .externalNativeBuild/ 14 | .cxx/ 15 | *.apk 16 | output.json 17 | 18 | # IntelliJ 19 | *.iml 20 | .idea/ 21 | misc.xml 22 | deploymentTargetDropDown.xml 23 | render.experimental.xml 24 | 25 | # Keystore files 26 | *.jks 27 | *.keystore 28 | 29 | # Google Services (e.g. APIs or Firebase) 30 | google-services.json 31 | 32 | # Android Profiling 33 | *.hprof 34 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/adapters/AllFavoritesDataSources.kt: -------------------------------------------------------------------------------- 1 | package favorites.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import favorites.core.entities.FavoriteRepository 6 | import favorites.core.ports.AllFavoritesDataSourcesPort 7 | 8 | class AllFavoritesDataSources( 9 | private val dataSources: DataSources = DataSourcesImpl 10 | ) : AllFavoritesDataSourcesPort { 11 | override suspend fun getAllFavorites(): List { 12 | return dataSources.getAllFavorites().map { createFavoriteRepository(it) } 13 | } 14 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/adapters/FavoriteDataSources.kt: -------------------------------------------------------------------------------- 1 | package favorites.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import favorites.core.entities.FavoriteRepository 6 | import favorites.core.ports.FavoriteDataSourcesPort 7 | 8 | class FavoriteDataSources( 9 | private val dataSources: DataSources = DataSourcesImpl 10 | ) : FavoriteDataSourcesPort { 11 | override suspend fun removeFromFavorites(favoriteRepository: FavoriteRepository) { 12 | return dataSources.removeFromFavorites(favoriteRepository.githubRepositoryData) 13 | } 14 | } -------------------------------------------------------------------------------- /iosApp/iosApp/ContentView.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SwiftUI 3 | import ComposeApp 4 | 5 | struct ComposeView: UIViewControllerRepresentable { 6 | func makeUIViewController(context: Context) -> UIViewController { 7 | MainViewControllerKt.MainViewController() 8 | } 9 | 10 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {} 11 | } 12 | 13 | struct ContentView: View { 14 | var body: some View { 15 | ComposeView() 16 | .ignoresSafeArea(.keyboard) // Compose has own keyboard handler 17 | } 18 | } 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/adapters/Mapping.kt: -------------------------------------------------------------------------------- 1 | package home.adapters 2 | 3 | import GithubRepositoryData 4 | import home.core.entities.GithubRepository 5 | 6 | fun createGithubRepository(data: GithubRepositoryData) = GithubRepository( 7 | metadata = data, 8 | id = data.id ?: throw IllegalArgumentException("Missing GithubRepositoryData id"), 9 | name = data.name, 10 | ownerName = data.owner?.name, 11 | avatarUrl = data.owner?.avatarUrl, 12 | stargazersCount = data.stargazersCount, 13 | ) 14 | 15 | val GithubRepository.githubRepositoryData: GithubRepositoryData 16 | get() = metadata as GithubRepositoryData -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/models/GithubRepositoryData.kt: -------------------------------------------------------------------------------- 1 | import kotlinx.serialization.SerialName 2 | import kotlinx.serialization.Serializable 3 | 4 | @Serializable 5 | data class GithubRepositoryData( 6 | @SerialName("id") val id: Long? = null, 7 | @SerialName("private") val isPrivate: Boolean? = null, 8 | @SerialName("name") val name: String? = null, 9 | @SerialName("description") val description: String? = null, 10 | @SerialName("stargazers_count") val stargazersCount: Int? = null, 11 | @SerialName("languages_url") val languagesUrl: String? = null, 12 | @SerialName("owner") val owner: OwnerData? = null 13 | ) -------------------------------------------------------------------------------- /server/src/main/kotlin/com/aismail/project/Application.kt: -------------------------------------------------------------------------------- 1 | package com.aismail.project 2 | 3 | import Greeting 4 | import SERVER_PORT 5 | import io.ktor.server.application.* 6 | import io.ktor.server.engine.* 7 | import io.ktor.server.netty.* 8 | import io.ktor.server.response.* 9 | import io.ktor.server.routing.* 10 | 11 | fun main() { 12 | embeddedServer(Netty, port = SERVER_PORT, host = "0.0.0.0", module = Application::module) 13 | .start(wait = true) 14 | } 15 | 16 | fun Application.module() { 17 | routing { 18 | get("/") { 19 | call.respondText("Ktor: ${Greeting().greet()}") 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/adapters/Mapping.kt: -------------------------------------------------------------------------------- 1 | package favorites.adapters 2 | 3 | import GithubRepositoryData 4 | import favorites.core.entities.FavoriteRepository 5 | 6 | internal fun createFavoriteRepository(data: GithubRepositoryData) = FavoriteRepository( 7 | metadata = data, 8 | id = data.id ?: throw IllegalArgumentException("Missing GithubRepositoryData id"), 9 | name = data.name, 10 | ownerName = data.owner?.name, 11 | avatarUrl = data.owner?.avatarUrl, 12 | stargazersCount = data.stargazersCount, 13 | ) 14 | 15 | val FavoriteRepository.githubRepositoryData: GithubRepositoryData 16 | get() = metadata as GithubRepositoryData -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/core/scenarios/AllFavoritesBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package favorites.core.scenarios 2 | 3 | import favorites.core.entities.FavoriteRepository 4 | import favorites.core.ports.AllFavoritesStatePort 5 | import favorites.core.ports.FavoriteStatePort 6 | 7 | 8 | suspend fun AllFavoritesStatePort.listAll( 9 | favoritePortFactory: (FavoriteRepository) -> FavoriteStatePort 10 | ) { 11 | progress = true 12 | runCatching { dataSources.getAllFavorites() } 13 | .mapCatching { it.map(favoritePortFactory) } 14 | .onFailure { error = it } 15 | .onSuccess { favorites.clear(); favorites.addAll(it) } 16 | progress = false 17 | } -------------------------------------------------------------------------------- /server/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | alias(libs.plugins.kotlinJvm) 3 | alias(libs.plugins.ktor) 4 | application 5 | } 6 | 7 | group = "com.aismail.project" 8 | version = "1.0.0" 9 | application { 10 | mainClass.set("com.aismail.project.ApplicationKt") 11 | applicationDefaultJvmArgs = listOf("-Dio.ktor.development=${extra["io.ktor.development"] ?: "false"}") 12 | } 13 | 14 | dependencies { 15 | implementation(projects.shared) 16 | implementation(libs.logback) 17 | implementation(libs.ktor.server.core) 18 | implementation(libs.ktor.server.netty) 19 | testImplementation(libs.ktor.server.tests) 20 | testImplementation(libs.kotlin.test.junit) 21 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/adapters/FavoriteState.kt: -------------------------------------------------------------------------------- 1 | package favorites.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateOf 5 | import androidx.compose.runtime.setValue 6 | import favorites.core.entities.FavoriteRepository 7 | import favorites.core.ports.FavoriteDataSourcesPort 8 | import favorites.core.ports.FavoriteStatePort 9 | 10 | class FavoriteState( 11 | override val favoriteRepository: FavoriteRepository, 12 | override val dataSources: FavoriteDataSourcesPort = FavoriteDataSources() 13 | ) : FavoriteStatePort { 14 | override var progress by mutableStateOf(false) 15 | override var error: Throwable? by mutableStateOf(null) 16 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/navigation/adapters/NavigationState.kt: -------------------------------------------------------------------------------- 1 | package navigation.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateOf 5 | import androidx.compose.runtime.setValue 6 | import navigation.core.Screens 7 | import navigation.core.ports.NavigationDataSourcePort 8 | import navigation.core.ports.NavigationStatePort 9 | import shared.adapters.StateHolder 10 | 11 | class NavigationState( 12 | override val dataSourcePort: NavigationDataSourcePort = NavigationDataSources(), 13 | ) : NavigationStatePort { 14 | override var screen by mutableStateOf(Screens.Splash) 15 | override var state by mutableStateOf?>(null) 16 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/adapters/HomeDataSources.kt: -------------------------------------------------------------------------------- 1 | package home.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import home.core.entities.GithubRepository 6 | import home.core.ports.HomeDataSourcesPort 7 | 8 | class HomeDataSources( 9 | private val dataSources: DataSources = DataSourcesImpl 10 | ) : HomeDataSourcesPort { 11 | override suspend fun getAllRepositories(): List { 12 | return dataSources.getAllGithubRepositories().data.map { createGithubRepository(it) } 13 | } 14 | 15 | override suspend fun getAllFavorites(): List { 16 | return dataSources.getAllFavorites().map { createGithubRepository(it) } 17 | } 18 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/adapters/HomeState.kt: -------------------------------------------------------------------------------- 1 | package home.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateListOf 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.compose.runtime.setValue 7 | import home.core.ports.GithubRepositoryStatePort 8 | import home.core.ports.HomeDataSourcesPort 9 | import home.core.ports.HomeStatePort 10 | 11 | class HomeState( 12 | override val dataSourcePort: HomeDataSourcesPort = HomeDataSources() 13 | ) : HomeStatePort { 14 | override var progress by mutableStateOf(false) 15 | override var error by mutableStateOf(null) 16 | override val repositories = mutableStateListOf() 17 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/adapters/GithubRepositoryDataSources.kt: -------------------------------------------------------------------------------- 1 | package home.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import home.core.entities.GithubRepository 6 | import home.core.ports.GithubRepositoryDataSourcesPort 7 | 8 | class GithubRepositoryDataSources( 9 | private val dataSources: DataSources = DataSourcesImpl 10 | ) : GithubRepositoryDataSourcesPort { 11 | 12 | override suspend fun addToFavorites(repository: GithubRepository) { 13 | dataSources.addToFavorites(repository.githubRepositoryData) 14 | } 15 | 16 | override suspend fun removeFromFavorites(repository: GithubRepository) { 17 | dataSources.removeFromFavorites(repository.githubRepositoryData) 18 | } 19 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/adapters/LoginState.kt: -------------------------------------------------------------------------------- 1 | package login.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateOf 5 | import androidx.compose.runtime.setValue 6 | import androidx.lifecycle.ViewModel 7 | import login.core.ports.LoginDataSourcePort 8 | import login.core.ports.LoginStatePort 9 | 10 | class LoginState( 11 | override val dataSourcePort: LoginDataSourcePort = LoginDataSource() 12 | ) : ViewModel(), LoginStatePort { 13 | override var userName by mutableStateOf(null) 14 | override var password by mutableStateOf(null) 15 | override var progress by mutableStateOf(false) 16 | override var result by mutableStateOf(null) 17 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/adapters/LoginDataSource.kt: -------------------------------------------------------------------------------- 1 | package login.adapters 2 | 3 | import data.DataSources 4 | import data.DataSourcesImpl 5 | import login.core.User 6 | import login.core.ports.LoginDataSourcePort 7 | 8 | class LoginDataSource( 9 | private val dataSources: DataSources = DataSourcesImpl 10 | ) : LoginDataSourcePort { 11 | override suspend fun getUsernameValidation() = dataSources.getUsernameValidation() 12 | override suspend fun getPasswordValidations() = dataSources.getPasswordValidations() 13 | override suspend fun saveUser(user: User) = dataSources.saveUser(user.userData) 14 | override suspend fun login(username: String?, password: String?) = 15 | createUser(dataSources.postLogin(username, password)) 16 | } -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-appleMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-appleTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-iosMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-iosTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-nativeMain.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/.composeApp-nativeTest.cinteropLibraries: -------------------------------------------------------------------------------- 1 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.kotlinx-atomicfu-0.23.2-nativeMain-cinterop/org.jetbrains.kotlinx_atomicfu-cinterop-interop-yBS35w.klib 2 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/org.jetbrains.compose.ui-ui-uikit-1.6.11-uikitMain-cinterop/org.jetbrains.compose.ui_ui-uikit-cinterop-utils-oguluQ.klib 3 | /Users/ahmedadelismail/AndroidStudioProjects/KMM-Compose-2024/.kotlin/metadata/kotlinTransformedCInteropMetadataLibraries/io.ktor-ktor-utils-2.3.12-iosMain-cinterop/io.ktor_ktor-utils-cinterop-threadUtils-TE4abA.klib -------------------------------------------------------------------------------- /composeApp/src/androidMain/kotlin/com/aismail/project/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.aismail.project 2 | 3 | import App 4 | import android.os.Bundle 5 | import androidx.activity.ComponentActivity 6 | import androidx.activity.compose.BackHandler 7 | import androidx.activity.compose.setContent 8 | import navigation.OnBackPressedChannel 9 | 10 | class MainActivity : ComponentActivity() { 11 | 12 | private lateinit var backPressedChannel: OnBackPressedChannel 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContent { 17 | 18 | App { backPressedChannel = it.value } 19 | 20 | BackHandler(backPressedChannel.isBackPressActive) { 21 | backPressedChannel.onBackPressed?.invoke() 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/adapters/GithubRepositoryState.kt: -------------------------------------------------------------------------------- 1 | package home.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateOf 5 | import androidx.compose.runtime.setValue 6 | import home.core.entities.GithubRepository 7 | import home.core.ports.GithubRepositoryDataSourcesPort 8 | import home.core.ports.GithubRepositoryStatePort 9 | 10 | class GithubRepositoryState( 11 | githubRepository: GithubRepository, 12 | override val dataSourcePort: GithubRepositoryDataSourcesPort = GithubRepositoryDataSources() 13 | ) : GithubRepositoryStatePort { 14 | override var isFavorite by mutableStateOf(false) 15 | override val repository by mutableStateOf(githubRepository) 16 | override var progress by mutableStateOf(false) 17 | override var error by mutableStateOf(null) 18 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/InMemoryCache.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("UNCHECKED_CAST") 2 | 3 | package data 4 | 5 | import androidx.annotation.VisibleForTesting 6 | import kotlin.properties.ReadWriteProperty 7 | import kotlin.reflect.KProperty 8 | 9 | object InMemoryCache { 10 | val cache = mutableMapOf() 11 | 12 | @VisibleForTesting 13 | fun clear() { 14 | cache.clear() 15 | } 16 | } 17 | 18 | fun cache(key: String, onChanged: ((T?) -> Unit)? = null) = 19 | object : ReadWriteProperty { 20 | override fun getValue(thisRef: Any?, property: KProperty<*>): T? { 21 | return InMemoryCache.cache[key] as? T? 22 | } 23 | 24 | override fun setValue(thisRef: Any?, property: KProperty<*>, value: T?) { 25 | InMemoryCache.cache[key] = value 26 | onChanged?.invoke(value) 27 | } 28 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/adapters/AllFavoritesState.kt: -------------------------------------------------------------------------------- 1 | package favorites.adapters 2 | 3 | import androidx.compose.runtime.getValue 4 | import androidx.compose.runtime.mutableStateListOf 5 | import androidx.compose.runtime.mutableStateOf 6 | import androidx.compose.runtime.setValue 7 | import favorites.core.ports.AllFavoritesDataSourcesPort 8 | import favorites.core.ports.AllFavoritesStatePort 9 | import favorites.core.ports.FavoriteStatePort 10 | import shared.adapters.Clearable 11 | 12 | class AllFavoritesState( 13 | override val dataSources: AllFavoritesDataSourcesPort = AllFavoritesDataSources() 14 | ) : AllFavoritesStatePort, Clearable { 15 | override var favorites = mutableStateListOf() 16 | override var progress by mutableStateOf(false) 17 | override var error by mutableStateOf(null) 18 | override fun clear() { 19 | favorites.clear() 20 | } 21 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "AIsmailProject" 2 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 3 | 4 | pluginManagement { 5 | repositories { 6 | google { 7 | mavenContent { 8 | includeGroupAndSubgroups("androidx") 9 | includeGroupAndSubgroups("com.android") 10 | includeGroupAndSubgroups("com.google") 11 | } 12 | } 13 | mavenCentral() 14 | gradlePluginPortal() 15 | } 16 | } 17 | 18 | dependencyResolutionManagement { 19 | repositories { 20 | google { 21 | mavenContent { 22 | includeGroupAndSubgroups("androidx") 23 | includeGroupAndSubgroups("com.android") 24 | includeGroupAndSubgroups("com.google") 25 | } 26 | } 27 | mavenCentral() 28 | } 29 | } 30 | 31 | include(":composeApp") 32 | include(":server") 33 | include(":shared") -------------------------------------------------------------------------------- /shared/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi 2 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 3 | 4 | plugins { 5 | alias(libs.plugins.kotlinMultiplatform) 6 | alias(libs.plugins.androidLibrary) 7 | } 8 | 9 | kotlin { 10 | androidTarget { 11 | @OptIn(ExperimentalKotlinGradlePluginApi::class) 12 | compilerOptions { 13 | jvmTarget.set(JvmTarget.JVM_11) 14 | } 15 | } 16 | 17 | iosX64() 18 | iosArm64() 19 | iosSimulatorArm64() 20 | 21 | jvm() 22 | 23 | sourceSets { 24 | commonMain.dependencies { 25 | // put your Multiplatform dependencies here 26 | } 27 | } 28 | } 29 | 30 | android { 31 | namespace = "com.aismail.project.shared" 32 | compileSdk = libs.versions.android.compileSdk.get().toInt() 33 | compileOptions { 34 | sourceCompatibility = JavaVersion.VERSION_11 35 | targetCompatibility = JavaVersion.VERSION_11 36 | } 37 | defaultConfig { 38 | minSdk = libs.versions.android.minSdk.get().toInt() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/scenarios/GithubRepositoryBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package home.core.scenarios 2 | 3 | import home.core.entities.GithubRepository 4 | import home.core.ports.GithubRepositoryStatePort 5 | 6 | 7 | suspend fun GithubRepositoryStatePort.initialize(favorites: List): GithubRepositoryStatePort { 8 | error = null 9 | progress = true 10 | isFavorite = favorites.any { it.id == repository.id } 11 | progress = false 12 | return this 13 | } 14 | 15 | suspend fun GithubRepositoryStatePort.addToFavorites() { 16 | if (progress) return 17 | error = null 18 | progress = true 19 | runCatching { dataSourcePort.addToFavorites(repository) } 20 | .onSuccess { isFavorite = true } 21 | .onFailure { error = it } 22 | progress = false 23 | } 24 | 25 | suspend fun GithubRepositoryStatePort.removeFromFavorites() { 26 | if (progress) return 27 | error = null 28 | progress = true 29 | runCatching { dataSourcePort.removeFromFavorites(repository) } 30 | .onSuccess { isFavorite = false } 31 | .onFailure { error = it } 32 | progress = false 33 | } 34 | 35 | -------------------------------------------------------------------------------- /composeApp/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/splash/SplashScreen.kt: -------------------------------------------------------------------------------- 1 | package splash 2 | 3 | import Greeting 4 | import aismailproject.composeapp.generated.resources.Res 5 | import aismailproject.composeapp.generated.resources.compose_multiplatform 6 | import androidx.compose.animation.AnimatedVisibility 7 | import androidx.compose.foundation.Image 8 | import androidx.compose.foundation.layout.Column 9 | import androidx.compose.foundation.layout.fillMaxWidth 10 | import androidx.compose.material.Text 11 | import androidx.compose.runtime.Composable 12 | import androidx.compose.runtime.remember 13 | import androidx.compose.ui.Alignment 14 | import androidx.compose.ui.Modifier 15 | import org.jetbrains.compose.resources.painterResource 16 | 17 | @Composable 18 | fun SplashScreen() { 19 | Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { 20 | AnimatedVisibility(true) { 21 | val greeting = remember { Greeting().greet() } 22 | Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) { 23 | Image(painterResource(Res.drawable.compose_multiplatform), null) 24 | Text("Compose: $greeting") 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/core/scenarios/LoginBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package login.core.scenarios 2 | 3 | import login.core.ports.LoginStatePort 4 | import login.core.ports.LoginStatePort.Result.Error 5 | import login.core.ports.LoginStatePort.Result.Success 6 | 7 | suspend fun LoginStatePort.login() { 8 | progress = true 9 | validate(userName, password) 10 | .mapCatching { dataSourcePort.login(it.first, it.second) } 11 | .mapCatching { dataSourcePort.saveUser(it) } 12 | .onSuccess { result = Success } 13 | .onFailure { result = Error(it) } 14 | progress = false 15 | } 16 | 17 | private suspend fun LoginStatePort.validate( 18 | userName: String?, 19 | password: String? 20 | ) = runCatching { 21 | if (!dataSourcePort.getUsernameValidation().all { validation -> validation(userName) }) { 22 | throw InvalidUsernameException 23 | } 24 | if (!dataSourcePort.getPasswordValidations().all { validation -> validation(password) }) { 25 | throw InvalidPasswordException 26 | } 27 | userName to password 28 | } 29 | 30 | // in real life, more errors to be handled, like generic and network errors 31 | object InvalidUsernameException : Exception() 32 | object InvalidPasswordException : Exception() -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/DataSources.kt: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import GithubRepositoryData 4 | import androidx.compose.runtime.State 5 | import data.models.AllGithubRepositoriesData 6 | import data.models.UserData 7 | 8 | /** 9 | * an interface to be implemented in unit tests and by different actual classes if required 10 | * 11 | * all methods are optional to make unit testing easier 12 | */ 13 | interface DataSources { 14 | suspend fun isLoggedIn(): Boolean = throw NotImplementedError() 15 | suspend fun getUsernameValidation(): List<(String?) -> Boolean> = throw NotImplementedError() 16 | suspend fun getPasswordValidations(): List<(String?) -> Boolean> = throw NotImplementedError() 17 | suspend fun postLogin(username: String?, password: String?): UserData = 18 | throw NotImplementedError() 19 | 20 | suspend fun saveUser(userData: UserData): Unit = throw NotImplementedError() 21 | suspend fun getAllGithubRepositories(): AllGithubRepositoriesData = throw NotImplementedError() 22 | suspend fun addToFavorites(repository: GithubRepositoryData): Unit = throw NotImplementedError() 23 | suspend fun removeFromFavorites(repository: GithubRepositoryData): Unit = 24 | throw NotImplementedError() 25 | 26 | suspend fun getAllFavorites(): List = throw NotImplementedError() 27 | fun observeOnFavoritesSize(): State = throw NotImplementedError() 28 | } 29 | 30 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/core/scenarios/HomeBusinessLogic.kt: -------------------------------------------------------------------------------- 1 | package home.core.scenarios 2 | 3 | import home.core.entities.GithubRepository 4 | import home.core.ports.GithubRepositoryStatePort 5 | import home.core.ports.HomeStatePort 6 | import kotlinx.coroutines.CoroutineDispatcher 7 | import kotlinx.coroutines.async 8 | import kotlinx.coroutines.coroutineScope 9 | 10 | suspend fun HomeStatePort.listAll( 11 | ioDispatcher: CoroutineDispatcher, 12 | repositoryPortFactory: (GithubRepository) -> GithubRepositoryStatePort 13 | ) = coroutineScope { 14 | error = null 15 | progress = true 16 | val repositories = async(ioDispatcher) { fetchAllRepositories() } 17 | val favorites = async(ioDispatcher) { fetchAllFavorites() } 18 | merge(repositories.await(), favorites.await(), repositoryPortFactory) 19 | } 20 | 21 | private suspend fun HomeStatePort.fetchAllRepositories() = 22 | runCatching { dataSourcePort.getAllRepositories() } 23 | .onFailure { error = it } 24 | .getOrDefault(listOf()) 25 | 26 | 27 | private suspend fun HomeStatePort.fetchAllFavorites() = 28 | runCatching { dataSourcePort.getAllFavorites() } 29 | .onFailure { error = it } 30 | .getOrDefault(listOf()) 31 | 32 | 33 | private suspend fun HomeStatePort.merge( 34 | fetchedRepositories: List, 35 | favorites: List, 36 | repositoryPortFactory: (GithubRepository) -> GithubRepositoryStatePort 37 | ) { 38 | if (fetchedRepositories.isNotEmpty()) { 39 | repositories.addAll(fetchedRepositories.map { repositoryPortFactory(it).initialize(favorites) }) 40 | } 41 | progress = false 42 | } 43 | 44 | -------------------------------------------------------------------------------- /iosApp/iosApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | CADisableMinimumFrameDurationOnPhone 24 | 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | 30 | UILaunchScreen 31 | 32 | UIRequiredDeviceCapabilities 33 | 34 | armv7 35 | 36 | UISupportedInterfaceOrientations 37 | 38 | UIInterfaceOrientationPortrait 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UISupportedInterfaceOrientations~ipad 43 | 44 | UIInterfaceOrientationPortrait 45 | UIInterfaceOrientationPortraitUpsideDown 46 | UIInterfaceOrientationLandscapeLeft 47 | UIInterfaceOrientationLandscapeRight 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a POC project to clarify how Hexagonal architecture combined with DDD can acheive more than 80% of the code to be KMM & Compose while platforms required code will be limited to edge cases and depending on there libraries for data-sources related code 2 | 3 | 4 | Screenshot 2024-07-10 at 1 58 11 AM 5 | 6 | Screenshot 2024-07-10 at 1 50 29 AM 7 | 8 | 9 | ========= 10 | 11 | This is a Kotlin Multiplatform project targeting Android, iOS, Desktop, Server. 12 | 13 | * `/composeApp` is for code that will be shared across your Compose Multiplatform applications. 14 | It contains several subfolders: 15 | - `commonMain` is for code that’s common for all targets. 16 | - Other folders are for Kotlin code that will be compiled for only the platform indicated in the folder name. 17 | For example, if you want to use Apple’s CoreCrypto for the iOS part of your Kotlin app, 18 | `iosMain` would be the right folder for such calls. 19 | 20 | * `/iosApp` contains iOS applications. Even if you’re sharing your UI with Compose Multiplatform, 21 | you need this entry point for your iOS app. This is also where you should add SwiftUI code for your project. 22 | 23 | * `/server` is for the Ktor server application. 24 | 25 | * `/shared` is for the code that will be shared between all targets in the project. 26 | The most important subfolder is `commonMain`. If preferred, you can add code to the platform-specific folders here too. 27 | 28 | Learn more about [Kotlin Multiplatform](https://www.jetbrains.com/help/kotlin-multiplatform-dev/get-started.html)… 29 | 30 | 31 | -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | agp = "8.5.0-rc01" 3 | android-compileSdk = "34" 4 | android-minSdk = "24" 5 | android-targetSdk = "34" 6 | androidx-activityCompose = "1.9.0" 7 | androidx-appcompat = "1.7.0" 8 | androidx-constraintlayout = "2.1.4" 9 | androidx-core-ktx = "1.13.1" 10 | androidx-espresso-core = "3.6.0" 11 | androidx-material = "1.12.0" 12 | androidx-test-junit = "1.2.0" 13 | compose-plugin = "1.6.11" 14 | junit = "4.13.2" 15 | kamelImage = "0.9.5" 16 | kotlin = "2.0.0" 17 | kotlinxSerializationJson = "1.6.3" 18 | ktor = "2.3.12" 19 | lifecycleViewmodel = "2.8.3" 20 | logback = "1.5.6" 21 | 22 | [libraries] 23 | androidx-lifecycle-viewmodel = { module = "androidx.lifecycle:lifecycle-viewmodel", version.ref = "lifecycleViewmodel" } 24 | kamel-image = { module = "media.kamel:kamel-image", version.ref = "kamelImage" } 25 | kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotlin" } 26 | kotlin-test-junit = { module = "org.jetbrains.kotlin:kotlin-test-junit", version.ref = "kotlin" } 27 | junit = { group = "junit", name = "junit", version.ref = "junit" } 28 | androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidx-core-ktx" } 29 | androidx-test-junit = { group = "androidx.test.ext", name = "junit", version.ref = "androidx-test-junit" } 30 | androidx-espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "androidx-espresso-core" } 31 | androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "androidx-appcompat" } 32 | androidx-material = { group = "com.google.android.material", name = "material", version.ref = "androidx-material" } 33 | androidx-constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "androidx-constraintlayout" } 34 | androidx-activity-compose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" } 35 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" } 36 | logback = { module = "ch.qos.logback:logback-classic", version.ref = "logback" } 37 | ktor-server-core = { module = "io.ktor:ktor-server-core-jvm", version.ref = "ktor" } 38 | ktor-server-netty = { module = "io.ktor:ktor-server-netty-jvm", version.ref = "ktor" } 39 | ktor-server-tests = { module = "io.ktor:ktor-server-tests-jvm", version.ref = "ktor" } 40 | ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" } 41 | ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } 42 | ktor-client-darwin = { module = "io.ktor:ktor-client-darwin", version.ref = "ktor" } 43 | 44 | [plugins] 45 | androidApplication = { id = "com.android.application", version.ref = "agp" } 46 | androidLibrary = { id = "com.android.library", version.ref = "agp" } 47 | jetbrainsCompose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" } 48 | compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" } 49 | kotlinJvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } 50 | ktor = { id = "io.ktor.plugin", version.ref = "ktor" } 51 | kotlinMultiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/DataSourcesImpl.kt: -------------------------------------------------------------------------------- 1 | package data 2 | 3 | import GithubRepositoryData 4 | import OwnerData 5 | import data.models.AllGithubRepositoriesData 6 | import data.models.UserData 7 | import kotlinx.coroutines.delay 8 | 9 | /** 10 | * add expect when integrating with real data sources, if we had to 11 | * do platform specific logic 12 | * 13 | * as this is a sample project, all integration points are grouped in one file for now 14 | * for the sake of simplicity 15 | */ 16 | // TODO: data to be fetched from actual datasource 17 | object DataSourcesImpl : DataSources { 18 | 19 | private var userData by cache("data.userData") 20 | private var favorites by cache>("data.favorites") 21 | 22 | override suspend fun getUsernameValidation(): List<(String?) -> Boolean> { 23 | delay(1000) // simulate server delay 24 | return listOf( 25 | { it != null && it.length > 4 }, 26 | { it?.contains("@") == true }, 27 | ) 28 | } 29 | 30 | override suspend fun getPasswordValidations(): List<(String?) -> Boolean> { 31 | delay(1000) // simulate server delay 32 | return listOf({ it != null && it.length > 4 }) 33 | } 34 | 35 | override suspend fun postLogin(username: String?, password: String?): UserData { 36 | delay(2000) //simulate server delay 37 | return UserData(id = 0, token = "$username|$password") 38 | } 39 | 40 | override suspend fun saveUser(userData: UserData) { 41 | this.userData = userData 42 | } 43 | 44 | /** 45 | * in a real application we have to handle token refresh and expiration 46 | */ 47 | override suspend fun isLoggedIn(): Boolean { 48 | delay(1000) // simulate IO delay 49 | return userData != null 50 | } 51 | 52 | override suspend fun getAllGithubRepositories(): AllGithubRepositoriesData { 53 | // return Json.decodeFromString(GithubRepositoriesMockResponse) 54 | delay(3000) //simulate server delay 55 | return AllGithubRepositoriesData(data = (1..500).map { mockGithubRepository(it) }) 56 | } 57 | 58 | override suspend fun addToFavorites(repository: GithubRepositoryData) { 59 | delay(1000) // simulate IO delay 60 | favorites = favorites.orEmpty() + repository 61 | } 62 | 63 | override suspend fun removeFromFavorites(repository: GithubRepositoryData) { 64 | delay(1000) // simulate IO delay 65 | favorites = favorites.orEmpty() - repository 66 | } 67 | 68 | override suspend fun getAllFavorites(): List { 69 | delay(1000) // simulate IO delay 70 | return favorites.orEmpty() 71 | } 72 | 73 | private fun mockGithubRepository(id: Int = 1) = GithubRepositoryData( 74 | id = id.toLong(), 75 | name = "Github Repository $id", 76 | isPrivate = false, 77 | description = "Github Repository $id description section", 78 | stargazersCount = id * 1000, 79 | languagesUrl = "https://api.github.com/repos/octocat/boysenberry-repo-1/languages", 80 | owner = OwnerData( 81 | id = (id * 3000).toLong(), 82 | isPrivate = false, 83 | name = "Author $id", 84 | avatarUrl = "https://picsum.photos/${ratio()}/${ratio()}" 85 | ) 86 | ) 87 | 88 | private fun ratio(): Int = (150..300).random() 89 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/App.kt: -------------------------------------------------------------------------------- 1 | import androidx.compose.material.MaterialTheme 2 | import androidx.compose.material.Surface 3 | import androidx.compose.runtime.Composable 4 | import androidx.compose.runtime.LaunchedEffect 5 | import androidx.compose.runtime.getValue 6 | import androidx.compose.runtime.mutableStateOf 7 | import androidx.compose.runtime.remember 8 | import androidx.compose.runtime.rememberCoroutineScope 9 | import favorites.adapters.AllFavoritesState 10 | import favorites.ui.FavoritesScreen 11 | import home.adapters.HomeState 12 | import home.ui.HomeScreen 13 | import kotlinx.coroutines.Dispatchers 14 | import kotlinx.coroutines.IO 15 | import kotlinx.coroutines.launch 16 | import login.adapters.LoginState 17 | import login.ui.LoginScreen 18 | import navigation.OnBackPressedChannel 19 | import navigation.Provider 20 | import navigation.adapters.NavigationState 21 | import navigation.core.Screens.Favorites 22 | import navigation.core.Screens.Home 23 | import navigation.core.Screens.Login 24 | import navigation.core.Screens.Splash 25 | import navigation.core.initialize 26 | import org.jetbrains.compose.ui.tooling.preview.Preview 27 | import shared.adapters.StateHolder 28 | import splash.SplashScreen 29 | 30 | private val backChannelProvider = Provider(OnBackPressedChannel()) 31 | 32 | @Composable 33 | @Preview 34 | fun App(onBackPressedProvider: @Composable (Provider) -> Unit = {}) { 35 | MaterialTheme { 36 | Surface(color = MaterialTheme.colors.background) { 37 | onBackPressedProvider(backChannelProvider) 38 | val scope = rememberCoroutineScope() 39 | val navigationState by remember { mutableStateOf(NavigationState()) } 40 | LaunchedEffect(Unit) { 41 | scope.launch(Dispatchers.IO) { 42 | navigationState.initialize() 43 | } 44 | } 45 | Screen(navigationState) 46 | } 47 | } 48 | } 49 | 50 | @Composable 51 | fun Screen( 52 | navigationState: NavigationState, 53 | ) { 54 | when (navigationState.screen) { 55 | 56 | Splash -> { 57 | backChannelProvider.value.onBackPressed = null 58 | navigationState.state = null 59 | SplashScreen() 60 | } 61 | 62 | Login -> { 63 | backChannelProvider.value.onBackPressed = null 64 | val holder = StateHolder("LoginState", LoginState()) 65 | navigationState.state = holder 66 | LoginScreen( 67 | state = holder.state(), 68 | onSuccess = { 69 | holder.clear() 70 | navigationState.screen = Home 71 | }, 72 | ) 73 | } 74 | 75 | Home -> { 76 | backChannelProvider.value.onBackPressed = null 77 | val holder = StateHolder("HomeState", HomeState()) 78 | navigationState.state = holder 79 | HomeScreen( 80 | state = holder.state(), 81 | onFavoritesClicked = { navigationState.screen = Favorites }, 82 | ) 83 | } 84 | 85 | Favorites -> { 86 | val holder = StateHolder("AllFavoritesState", AllFavoritesState()) 87 | navigationState.state = holder 88 | backChannelProvider.value.onBackPressed = { 89 | holder.clear() 90 | navigationState.screen = Home 91 | } 92 | FavoritesScreen( 93 | state = holder.state(), 94 | onBackPress = { 95 | backChannelProvider.value.onBackPressed?.invoke() 96 | } 97 | ) 98 | } 99 | } 100 | } 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /composeApp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.compose.desktop.application.dsl.TargetFormat 2 | import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi 3 | import org.jetbrains.kotlin.gradle.dsl.JvmTarget 4 | 5 | plugins { 6 | alias(libs.plugins.kotlinMultiplatform) 7 | alias(libs.plugins.androidApplication) 8 | alias(libs.plugins.jetbrainsCompose) 9 | alias(libs.plugins.compose.compiler) 10 | kotlin("plugin.serialization") version "2.0.0" 11 | } 12 | 13 | kotlin { 14 | androidTarget { 15 | @OptIn(ExperimentalKotlinGradlePluginApi::class) 16 | compilerOptions { 17 | jvmTarget.set(JvmTarget.JVM_11) 18 | } 19 | } 20 | 21 | jvm("desktop") 22 | 23 | listOf( 24 | iosX64(), 25 | iosArm64(), 26 | iosSimulatorArm64() 27 | ).forEach { iosTarget -> 28 | iosTarget.binaries.framework { 29 | baseName = "ComposeApp" 30 | isStatic = true 31 | } 32 | } 33 | 34 | sourceSets { 35 | val desktopMain by getting 36 | 37 | androidMain.dependencies { 38 | implementation(compose.preview) 39 | implementation(libs.ktor.client.okhttp) 40 | implementation( 41 | libs.androidx.activity.compose.get() 42 | .let { "${it.module}:${it.versionConstraint.requiredVersion}" }) { 43 | exclude( 44 | group = "androidx.lifecycle", 45 | module = "lifecycle-viewmodel-ktx" 46 | ) 47 | } 48 | } 49 | commonMain.dependencies { 50 | implementation(compose.runtime) 51 | implementation(compose.foundation) 52 | implementation(compose.material) 53 | implementation(compose.ui) 54 | implementation(compose.components.resources) 55 | implementation(compose.components.uiToolingPreview) 56 | implementation(projects.shared) 57 | implementation(libs.androidx.lifecycle.viewmodel) 58 | implementation(libs.kotlin.test) 59 | implementation(libs.kotlinx.serialization.json) 60 | implementation(libs.kamel.image) 61 | implementation(libs.ktor.client.core) 62 | } 63 | desktopMain.dependencies { 64 | implementation(compose.desktop.currentOs) 65 | implementation(libs.ktor.client.okhttp) 66 | } 67 | iosMain.dependencies { 68 | implementation(libs.ktor.client.darwin) 69 | } 70 | } 71 | } 72 | 73 | android { 74 | namespace = "com.aismail.project" 75 | compileSdk = libs.versions.android.compileSdk.get().toInt() 76 | 77 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 78 | sourceSets["main"].res.srcDirs("src/androidMain/res") 79 | sourceSets["main"].resources.srcDirs("src/commonMain/resources") 80 | 81 | defaultConfig { 82 | applicationId = "com.aismail.project" 83 | minSdk = libs.versions.android.minSdk.get().toInt() 84 | targetSdk = libs.versions.android.targetSdk.get().toInt() 85 | versionCode = 1 86 | versionName = "1.0" 87 | } 88 | packaging { 89 | resources { 90 | excludes += "/META-INF/{AL2.0,LGPL2.1}" 91 | } 92 | } 93 | buildTypes { 94 | getByName("release") { 95 | isMinifyEnabled = false 96 | } 97 | } 98 | compileOptions { 99 | sourceCompatibility = JavaVersion.VERSION_11 100 | targetCompatibility = JavaVersion.VERSION_11 101 | } 102 | buildFeatures { 103 | compose = true 104 | } 105 | dependencies { 106 | debugImplementation(compose.uiTooling) 107 | } 108 | } 109 | 110 | compose.desktop { 111 | application { 112 | mainClass = "MainKt" 113 | 114 | nativeDistributions { 115 | targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb) 116 | packageName = "com.aismail.project" 117 | packageVersion = "1.0.0" 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/composeResources/drawable/compose-multiplatform.xml: -------------------------------------------------------------------------------- 1 | 6 | 10 | 14 | 18 | 24 | 30 | 36 | -------------------------------------------------------------------------------- /composeApp/src/androidMain/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 65 | 70 | 75 | 80 | 85 | 90 | 95 | 100 | 105 | 110 | 115 | 120 | 125 | 130 | 135 | 140 | 145 | 150 | 155 | 160 | 165 | 170 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/login/ui/LoginScreen.kt: -------------------------------------------------------------------------------- 1 | package login.ui 2 | 3 | import androidx.compose.foundation.layout.Column 4 | import androidx.compose.foundation.layout.fillMaxSize 5 | import androidx.compose.foundation.layout.fillMaxWidth 6 | import androidx.compose.foundation.layout.height 7 | import androidx.compose.foundation.layout.padding 8 | import androidx.compose.foundation.text.KeyboardActions 9 | import androidx.compose.material.Button 10 | import androidx.compose.material.ButtonDefaults 11 | import androidx.compose.material.LinearProgressIndicator 12 | import androidx.compose.material.MaterialTheme 13 | import androidx.compose.material.OutlinedTextField 14 | import androidx.compose.material.Text 15 | import androidx.compose.material.TopAppBar 16 | import androidx.compose.runtime.Composable 17 | import androidx.compose.runtime.LaunchedEffect 18 | import androidx.compose.runtime.remember 19 | import androidx.compose.runtime.rememberCoroutineScope 20 | import androidx.compose.ui.Modifier 21 | import androidx.compose.ui.focus.FocusRequester 22 | import androidx.compose.ui.focus.focusRequester 23 | import androidx.compose.ui.graphics.Color 24 | import androidx.compose.ui.platform.LocalFocusManager 25 | import androidx.compose.ui.text.input.PasswordVisualTransformation 26 | import androidx.compose.ui.unit.dp 27 | import kotlinx.coroutines.CoroutineDispatcher 28 | import kotlinx.coroutines.Dispatchers 29 | import kotlinx.coroutines.IO 30 | import kotlinx.coroutines.launch 31 | import login.core.ports.LoginStatePort 32 | import login.core.scenarios.InvalidPasswordException 33 | import login.core.scenarios.InvalidUsernameException 34 | import login.core.scenarios.login 35 | 36 | @Composable 37 | fun LoginScreen( 38 | state: LoginStatePort, 39 | onSuccess: () -> Unit, 40 | modifier: Modifier = Modifier, 41 | dispatcher: CoroutineDispatcher = Dispatchers.IO 42 | ) { 43 | val scope = rememberCoroutineScope() 44 | 45 | LoginScreenContent( 46 | userName = state.userName, 47 | password = state.password, 48 | progress = state.progress, 49 | result = state.result, 50 | onUsernameChanged = { state.userName = it }, 51 | onPasswordChanged = { state.password = it }, 52 | onLoginClicked = { scope.launch(dispatcher) { state.login() } }, 53 | onSuccess = onSuccess, 54 | modifier = modifier 55 | ) 56 | } 57 | 58 | 59 | @Composable 60 | fun LoginScreenContent( 61 | userName: String?, 62 | password: String?, 63 | progress: Boolean, 64 | result: LoginStatePort.Result?, 65 | onUsernameChanged: (String?) -> Unit, 66 | onPasswordChanged: (String?) -> Unit, 67 | onLoginClicked: () -> Unit, 68 | onSuccess: () -> Unit, 69 | modifier: Modifier = Modifier 70 | ) { 71 | if (result == LoginStatePort.Result.Success) { 72 | onSuccess() 73 | } else { 74 | val usernameFocusRequester = remember { FocusRequester() } 75 | val passwordFocusRequester = remember { FocusRequester() } 76 | 77 | Column(modifier = modifier.fillMaxSize()) { 78 | TopAppBar(title = { Text(text = "Login", modifier = Modifier.fillMaxWidth()) }) 79 | if (progress) LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) 80 | Column( 81 | modifier = Modifier.fillMaxSize().padding(16.dp), 82 | verticalArrangement = androidx.compose.foundation.layout.Arrangement.Center, 83 | ) { 84 | UsernameOutlinedTextField( 85 | userName, 86 | result, 87 | usernameFocusRequester, 88 | passwordFocusRequester, 89 | onUsernameChanged 90 | ) 91 | PasswordOutlinedTextField( 92 | password, 93 | result, 94 | passwordFocusRequester, 95 | onPasswordChanged, 96 | onLoginClicked 97 | ) 98 | LoginButton(progress, onLoginClicked) 99 | } 100 | } 101 | 102 | LaunchedEffect(Unit) { 103 | usernameFocusRequester.requestFocus() 104 | } 105 | } 106 | } 107 | 108 | @Composable 109 | private fun UsernameOutlinedTextField( 110 | userName: String?, 111 | result: LoginStatePort.Result?, 112 | usernameFocusRequester: FocusRequester, 113 | passwordFocusRequester: FocusRequester, 114 | onUsernameChanged: (String?) -> Unit 115 | ) { 116 | OutlinedTextField( 117 | modifier = Modifier 118 | .focusRequester(usernameFocusRequester) 119 | .fillMaxWidth() 120 | .height(80.dp) 121 | .padding(bottom = 16.dp), 122 | value = userName.orEmpty(), 123 | singleLine = true, 124 | label = { Text(text = "Username") }, 125 | isError = result is LoginStatePort.Result.Error && result.error is InvalidUsernameException, 126 | onValueChange = onUsernameChanged, 127 | keyboardActions = KeyboardActions(onDone = { passwordFocusRequester.requestFocus() }) 128 | ) 129 | } 130 | 131 | @Composable 132 | private fun PasswordOutlinedTextField( 133 | password: String?, 134 | result: LoginStatePort.Result?, 135 | focusRequester: FocusRequester, 136 | onPasswordChanged: (String?) -> Unit, 137 | onLoginClicked: () -> Unit 138 | ) { 139 | val focusManager = LocalFocusManager.current 140 | OutlinedTextField( 141 | modifier = Modifier 142 | .focusRequester(focusRequester) 143 | .fillMaxWidth() 144 | .height(80.dp) 145 | .padding(bottom = 16.dp), 146 | value = password.orEmpty(), 147 | label = { Text(text = "Password") }, 148 | singleLine = true, 149 | visualTransformation = PasswordVisualTransformation(), 150 | isError = result is LoginStatePort.Result.Error && result.error is InvalidPasswordException, 151 | onValueChange = onPasswordChanged, 152 | keyboardActions = KeyboardActions(onDone = { 153 | focusManager.clearFocus() 154 | onLoginClicked() 155 | }) 156 | ) 157 | } 158 | 159 | @Composable 160 | private fun LoginButton(progress: Boolean, onLoginClicked: () -> Unit) { 161 | val focusManager = LocalFocusManager.current 162 | Button( 163 | modifier = Modifier 164 | .fillMaxWidth() 165 | .height(80.dp) 166 | .padding(bottom = 16.dp), 167 | colors = ButtonDefaults.buttonColors(backgroundColor = if (!progress) MaterialTheme.colors.primary else Color.Gray), 168 | onClick = { 169 | if (!progress) { 170 | onLoginClicked() 171 | focusManager.clearFocus() 172 | } 173 | }) { 174 | Text(text = "Login") 175 | } 176 | } -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/data/mocks/MockServerResponse.kt: -------------------------------------------------------------------------------- 1 | package data.mocks 2 | 3 | val GithubRepositoriesMockResponse = """ 4 | {"data" : [ 5 | { 6 | "id": 132935648, 7 | "private": false, 8 | "name": "boysenberry-repo-1", 9 | "description": "Testing", 10 | "stargazers_count": 3, 11 | "languages_url": "https://api.github.com/repos/octocat/boysenberry-repo-1/languages", 12 | "owner": { 13 | "id": 583231, 14 | "private": false, 15 | "name": "octocat", 16 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 17 | } 18 | }, 19 | { 20 | "id": 1296269, 21 | "private": false, 22 | "name": "Hello-World", 23 | "description": "My first repository on GitHub!", 24 | "stargazers_count": 1582, 25 | "languages_url": "https://api.github.com/repos/octocat/Hello-World/languages", 26 | "owner": { 27 | "id": 583231, 28 | "private": false, 29 | "name": "octocat", 30 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 31 | } 32 | }, 33 | { 34 | "id": 18221276, 35 | "private": false, 36 | "name": "git-consortium", 37 | "description": "This repo is for demonstration purposes only.", 38 | "stargazers_count": 4, 39 | "languages_url": "https://api.github.com/repos/octocat/git-consortium/languages", 40 | "owner": { 41 | "id": 583231, 42 | "private": false, 43 | "name": "octocat", 44 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 45 | } 46 | }, 47 | { 48 | "id": 54346856, 49 | "private": false, 50 | "name": "Spoon-Knife", 51 | "description": "This repo is for demonstration purposes only.", 52 | "stargazers_count": 10779, 53 | "languages_url": "https://api.github.com/repos/octocat/Spoon-Knife/languages", 54 | "owner": { 55 | "id": 583231, 56 | "private": false, 57 | "name": "octocat", 58 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 59 | } 60 | }, 61 | { 62 | "id": 20978623, 63 | "private": false, 64 | "name": "test-repo1", 65 | "description": "Test repo for demonstration purposes.", 66 | "stargazers_count": 0, 67 | "languages_url": "https://api.github.com/repos/octocat/test-repo1/languages", 68 | "owner": { 69 | "id": 583231, 70 | "private": false, 71 | "name": "octocat", 72 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 73 | } 74 | }, 75 | { 76 | "id": 45717250, 77 | "private": false, 78 | "name": "test-repo2", 79 | "description": "Another test repo for demonstration purposes.", 80 | "stargazers_count": 1, 81 | "languages_url": "https://api.github.com/repos/octocat/test-repo2/languages", 82 | "owner": { 83 | "id": 583231, 84 | "private": false, 85 | "name": "octocat", 86 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 87 | } 88 | }, 89 | { 90 | "id": 63537249, 91 | "private": false, 92 | "name": "test-repo3", 93 | "description": "Yet another test repo for demonstration purposes.", 94 | "stargazers_count": 2, 95 | "languages_url": "https://api.github.com/repos/octocat/test-repo3/languages", 96 | "owner": { 97 | "id": 583231, 98 | "private": false, 99 | "name": "octocat", 100 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 101 | } 102 | }, 103 | { 104 | "id": 796307, 105 | "private": false, 106 | "name": "Hello-World2", 107 | "description": "My second repository on GitHub!", 108 | "stargazers_count": 132, 109 | "languages_url": "https://api.github.com/repos/octocat/Hello-World2/languages", 110 | "owner": { 111 | "id": 583231, 112 | "private": false, 113 | "name": "octocat", 114 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 115 | } 116 | }, 117 | { 118 | "id": 1296201, 119 | "private": false, 120 | "name": "test-repo4", 121 | "description": "Another test repository.", 122 | "stargazers_count": 12, 123 | "languages_url": "https://api.github.com/repos/octocat/test-repo4/languages", 124 | "owner": { 125 | "id": 583231, 126 | "private": false, 127 | "name": "octocat", 128 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 129 | } 130 | }, 131 | { 132 | "id": 234837529, 133 | "private": false, 134 | "name": "test-repo5", 135 | "description": "Test repository for demo purposes.", 136 | "stargazers_count": 3, 137 | "languages_url": "https://api.github.com/repos/octocat/test-repo5/languages", 138 | "owner": { 139 | "id": 583231, 140 | "private": false, 141 | "name": "octocat", 142 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 143 | } 144 | }, 145 | { 146 | "id": 1347434, 147 | "private": false, 148 | "name": "test-repo6", 149 | "description": "Another demo test repository.", 150 | "stargazers_count": 0, 151 | "languages_url": "https://api.github.com/repos/octocat/test-repo6/languages", 152 | "owner": { 153 | "id": 583231, 154 | "private": false, 155 | "name": "octocat", 156 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 157 | } 158 | }, 159 | { 160 | "id": 767459, 161 | "private": false, 162 | "name": "Hello-World3", 163 | "description": "Third Hello World repository.", 164 | "stargazers_count": 45, 165 | "languages_url": "https://api.github.com/repos/octocat/Hello-World3/languages", 166 | "owner": { 167 | "id": 583231, 168 | "private": false, 169 | "name": "octocat", 170 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 171 | } 172 | }, 173 | { 174 | "id": 45157450, 175 | "private": false, 176 | "name": "test-repo7", 177 | "description": "Another repository for testing.", 178 | "stargazers_count": 7, 179 | "languages_url": "https://api.github.com/repos/octocat/test-repo7/languages", 180 | "owner": { 181 | "id": 583231, 182 | "private": false, 183 | "name": "octocat", 184 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 185 | } 186 | }, 187 | { 188 | "id": 659478, 189 | "private": false, 190 | "name": "Hello-World4", 191 | "description": "Fourth Hello World repository.", 192 | "stargazers_count": 98, 193 | "languages_url": "https://api.github.com/repos/octocat/Hello-World4/languages", 194 | "owner": { 195 | "id": 583231, 196 | "private": false, 197 | "name": "octocat", 198 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 199 | } 200 | }, 201 | { 202 | "id": 57956430, 203 | "private": false, 204 | "name": "test-repo8", 205 | "description": "Yet another test repository.", 206 | "stargazers_count": 5, 207 | "languages_url": "https://api.github.com/repos/octocat/test-repo8/languages", 208 | "owner": { 209 | "id": 583231, 210 | "private": false, 211 | "name": "octocat", 212 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 213 | } 214 | }, 215 | { 216 | "id": 65947822, 217 | "private": false, 218 | "name": "Hello-World5", 219 | "description": "Fifth Hello World repository.", 220 | "stargazers_count": 150, 221 | "languages_url": "https://api.github.com/repos/octocat/Hello-World5/languages", 222 | "owner": { 223 | "id": 583231, 224 | "private": false, 225 | "name": "octocat", 226 | "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4" 227 | } 228 | } 229 | ] 230 | } 231 | """.trimIndent() -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/favorites/ui/FavoritesScreen.kt: -------------------------------------------------------------------------------- 1 | package favorites.ui 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.clickable 5 | import androidx.compose.foundation.layout.Arrangement 6 | import androidx.compose.foundation.layout.Box 7 | import androidx.compose.foundation.layout.Column 8 | import androidx.compose.foundation.layout.Row 9 | import androidx.compose.foundation.layout.RowScope 10 | import androidx.compose.foundation.layout.fillMaxHeight 11 | import androidx.compose.foundation.layout.fillMaxSize 12 | import androidx.compose.foundation.layout.fillMaxWidth 13 | import androidx.compose.foundation.layout.height 14 | import androidx.compose.foundation.layout.padding 15 | import androidx.compose.foundation.layout.size 16 | import androidx.compose.foundation.lazy.LazyColumn 17 | import androidx.compose.foundation.lazy.items 18 | import androidx.compose.foundation.shape.CircleShape 19 | import androidx.compose.material.CircularProgressIndicator 20 | import androidx.compose.material.Divider 21 | import androidx.compose.material.Icon 22 | import androidx.compose.material.IconButton 23 | import androidx.compose.material.LinearProgressIndicator 24 | import androidx.compose.material.MaterialTheme 25 | import androidx.compose.material.Text 26 | import androidx.compose.material.TopAppBar 27 | import androidx.compose.material.icons.Icons 28 | import androidx.compose.material.icons.automirrored.filled.ArrowBack 29 | import androidx.compose.material.icons.filled.Favorite 30 | import androidx.compose.material.icons.filled.Lock 31 | import androidx.compose.material.icons.filled.Star 32 | import androidx.compose.material.icons.filled.Warning 33 | import androidx.compose.material.icons.sharp.Warning 34 | import androidx.compose.runtime.Composable 35 | import androidx.compose.runtime.LaunchedEffect 36 | import androidx.compose.runtime.rememberCoroutineScope 37 | import androidx.compose.ui.Alignment 38 | import androidx.compose.ui.Modifier 39 | import androidx.compose.ui.draw.clip 40 | import androidx.compose.ui.graphics.painter.Painter 41 | import androidx.compose.ui.layout.ContentScale 42 | import androidx.compose.ui.unit.dp 43 | import favorites.adapters.FavoriteState 44 | import favorites.core.entities.FavoriteRepository 45 | import favorites.core.ports.AllFavoritesStatePort 46 | import favorites.core.ports.FavoriteStatePort 47 | import favorites.core.scenarios.listAll 48 | import io.kamel.core.Resource 49 | import io.kamel.image.asyncPainterResource 50 | import kotlinx.coroutines.CoroutineDispatcher 51 | import kotlinx.coroutines.Dispatchers 52 | import kotlinx.coroutines.IO 53 | import kotlinx.coroutines.withContext 54 | 55 | private val imageModifier = 56 | Modifier.size(width = 70.dp, height = 76.dp).padding(4.dp).clip(CircleShape) 57 | 58 | private val imageProgressModifier = 59 | Modifier.size(width = 70.dp, height = 76.dp).padding(20.dp).clip(CircleShape) 60 | 61 | @Composable 62 | fun FavoritesScreen( 63 | state: AllFavoritesStatePort, 64 | modifier: Modifier = Modifier, 65 | ioDispatcher: CoroutineDispatcher = Dispatchers.IO, 66 | imageLoader: @Composable (String) -> Resource = { asyncPainterResource(it) }, 67 | onBackPress: () -> Unit, 68 | ) { 69 | 70 | val scope = rememberCoroutineScope() 71 | 72 | @Composable 73 | fun TopAppBarContent() { 74 | TopAppBar(title = { Text(text = "Favorites", modifier = Modifier.fillMaxWidth()) }, 75 | navigationIcon = { 76 | IconButton(onClick = onBackPress) { 77 | Icon(Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null) 78 | } 79 | }) 80 | } 81 | 82 | @Composable 83 | fun ListItemsContent( 84 | items: List?, 85 | error: Throwable?, 86 | onItemClicked: (FavoriteStatePort) -> Unit = {} 87 | ) { 88 | 89 | @Composable 90 | fun ErrorContent(error: Throwable) { 91 | 92 | @Composable 93 | fun ErrorText(error: Throwable) { 94 | Text( 95 | text = "An error occurred: ${error.message}", 96 | style = MaterialTheme.typography.subtitle1 97 | ) 98 | } 99 | 100 | @Composable 101 | fun ErrorIcon() { 102 | Icon( 103 | Icons.Filled.Warning, 104 | contentDescription = null, 105 | tint = MaterialTheme.colors.error, 106 | modifier = Modifier.size(64.dp) 107 | ) 108 | } 109 | 110 | Column( 111 | modifier = Modifier.fillMaxSize().padding(16.dp), 112 | verticalArrangement = Arrangement.Center, 113 | horizontalAlignment = Alignment.CenterHorizontally 114 | ) { 115 | ErrorIcon() 116 | ErrorText(error) 117 | } 118 | } 119 | 120 | @Composable 121 | fun EmptyContent() { 122 | Box( 123 | modifier = Modifier.fillMaxSize().padding(16.dp), 124 | contentAlignment = Alignment.Center 125 | ) { 126 | Text(text = "No Favorites", style = MaterialTheme.typography.h6) 127 | } 128 | } 129 | 130 | @Composable 131 | fun LoadedContent( 132 | listItems: List, onItemClicked: (FavoriteStatePort) -> Unit 133 | ) { 134 | 135 | @Composable 136 | fun ItemContent( 137 | item: FavoriteStatePort, onItemClicked: (FavoriteStatePort) -> Unit 138 | ) { 139 | 140 | @Composable 141 | fun ItemImageSection(imageUrl: String) { 142 | 143 | @Composable 144 | fun FetchedImage(painter: Painter) { 145 | Image( 146 | painter = painter, 147 | contentDescription = null, 148 | contentScale = ContentScale.Crop, 149 | modifier = imageModifier 150 | ) 151 | } 152 | 153 | @Composable 154 | fun ErrorImage() { 155 | Icon( 156 | Icons.Sharp.Warning, 157 | tint = MaterialTheme.colors.error, 158 | contentDescription = null, 159 | modifier = imageModifier 160 | ) 161 | } 162 | 163 | when (val resource = imageLoader(imageUrl)) { 164 | is Resource.Loading -> CircularProgressIndicator(modifier = imageProgressModifier) 165 | is Resource.Success -> FetchedImage(resource.value) 166 | is Resource.Failure -> ErrorImage() 167 | } 168 | } 169 | 170 | @Composable 171 | fun RowScope.ItemMiddleSection(githubRepository: FavoriteRepository) { 172 | Column( 173 | modifier = Modifier.fillMaxHeight().weight(10f).padding(8.dp), 174 | horizontalAlignment = Alignment.Start, 175 | verticalArrangement = Arrangement.Top 176 | ) { 177 | Text( 178 | text = githubRepository.name.orEmpty(), 179 | style = MaterialTheme.typography.subtitle1 180 | ) 181 | Text( 182 | text = githubRepository.ownerName.orEmpty(), 183 | style = MaterialTheme.typography.body2 184 | ) 185 | Icon( 186 | Icons.Filled.Favorite, 187 | tint = MaterialTheme.colors.primary, 188 | contentDescription = null, 189 | modifier = Modifier.fillMaxHeight() 190 | ) 191 | } 192 | } 193 | 194 | @Composable 195 | fun RowScope.ItemStarsSection(githubRepository: FavoriteRepository) { 196 | Column( 197 | modifier = Modifier.fillMaxHeight().weight(3f).padding(4.dp), 198 | horizontalAlignment = Alignment.End, 199 | verticalArrangement = Arrangement.SpaceEvenly 200 | ) { 201 | Icon( 202 | if (item.progress) Icons.Filled.Lock else Icons.Filled.Star, 203 | contentDescription = null, 204 | tint = MaterialTheme.colors.primary, 205 | modifier = Modifier.size(24.dp) 206 | ) 207 | Text( 208 | text = githubRepository.stargazersCount.toString(), 209 | style = MaterialTheme.typography.subtitle1 210 | ) 211 | } 212 | } 213 | 214 | Row( 215 | modifier = modifier.height(80.dp).padding(4.dp) 216 | .clickable { onItemClicked(item) }, 217 | verticalAlignment = Alignment.CenterVertically, 218 | ) { 219 | ItemImageSection(item.favoriteRepository.avatarUrl.orEmpty()) 220 | ItemMiddleSection(item.favoriteRepository) 221 | ItemStarsSection(item.favoriteRepository) 222 | } 223 | } 224 | 225 | LazyColumn { 226 | items(items = listItems, key = { it.favoriteRepository.id }) { item -> 227 | ItemContent(item = item, onItemClicked) 228 | Divider() 229 | } 230 | } 231 | } 232 | 233 | when { 234 | error != null -> ErrorContent(error) 235 | items.isNullOrEmpty() -> EmptyContent() 236 | else -> LoadedContent(items, onItemClicked) 237 | } 238 | } 239 | 240 | 241 | @Composable 242 | fun FavoritesScreenContent() { 243 | 244 | LaunchedEffect(Unit) { 245 | withContext(ioDispatcher) { 246 | state.listAll { FavoriteState(it) } 247 | } 248 | } 249 | 250 | Column(modifier = modifier.fillMaxSize()) { 251 | TopAppBarContent() 252 | if (state.progress) LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) 253 | ListItemsContent( 254 | items = state.favorites, error = state.error 255 | ) 256 | } 257 | } 258 | 259 | FavoritesScreenContent() 260 | } 261 | 262 | -------------------------------------------------------------------------------- /composeApp/src/commonMain/kotlin/home/ui/HomeScreen.kt: -------------------------------------------------------------------------------- 1 | package home.ui 2 | 3 | import androidx.compose.foundation.Image 4 | import androidx.compose.foundation.clickable 5 | import androidx.compose.foundation.layout.Arrangement 6 | import androidx.compose.foundation.layout.Box 7 | import androidx.compose.foundation.layout.Column 8 | import androidx.compose.foundation.layout.Row 9 | import androidx.compose.foundation.layout.RowScope 10 | import androidx.compose.foundation.layout.fillMaxHeight 11 | import androidx.compose.foundation.layout.fillMaxSize 12 | import androidx.compose.foundation.layout.fillMaxWidth 13 | import androidx.compose.foundation.layout.height 14 | import androidx.compose.foundation.layout.padding 15 | import androidx.compose.foundation.layout.size 16 | import androidx.compose.foundation.lazy.LazyColumn 17 | import androidx.compose.foundation.lazy.items 18 | import androidx.compose.foundation.shape.CircleShape 19 | import androidx.compose.material.AlertDialog 20 | import androidx.compose.material.Button 21 | import androidx.compose.material.CircularProgressIndicator 22 | import androidx.compose.material.Divider 23 | import androidx.compose.material.Icon 24 | import androidx.compose.material.IconButton 25 | import androidx.compose.material.LinearProgressIndicator 26 | import androidx.compose.material.MaterialTheme 27 | import androidx.compose.material.Text 28 | import androidx.compose.material.TopAppBar 29 | import androidx.compose.material.icons.Icons 30 | import androidx.compose.material.icons.filled.Favorite 31 | import androidx.compose.material.icons.filled.Star 32 | import androidx.compose.material.icons.filled.Warning 33 | import androidx.compose.material.icons.sharp.Warning 34 | import androidx.compose.runtime.Composable 35 | import androidx.compose.runtime.LaunchedEffect 36 | import androidx.compose.runtime.getValue 37 | import androidx.compose.runtime.mutableStateOf 38 | import androidx.compose.runtime.remember 39 | import androidx.compose.runtime.rememberCoroutineScope 40 | import androidx.compose.runtime.setValue 41 | import androidx.compose.ui.Alignment 42 | import androidx.compose.ui.Modifier 43 | import androidx.compose.ui.draw.clip 44 | import androidx.compose.ui.graphics.painter.Painter 45 | import androidx.compose.ui.layout.ContentScale 46 | import androidx.compose.ui.unit.dp 47 | import home.adapters.GithubRepositoryState 48 | import home.core.ports.GithubRepositoryStatePort 49 | import home.core.ports.HomeStatePort 50 | import home.core.scenarios.addToFavorites 51 | import home.core.scenarios.listAll 52 | import home.core.scenarios.removeFromFavorites 53 | import io.kamel.core.Resource 54 | import io.kamel.image.asyncPainterResource 55 | import kotlinx.coroutines.CoroutineDispatcher 56 | import kotlinx.coroutines.Dispatchers 57 | import kotlinx.coroutines.IO 58 | import kotlinx.coroutines.launch 59 | import kotlinx.coroutines.withContext 60 | 61 | 62 | private val imageModifier = Modifier 63 | .size(width = 70.dp, height = 76.dp) 64 | .padding(4.dp) 65 | .clip(CircleShape) 66 | 67 | private val imageProgressModifier = Modifier 68 | .size(width = 70.dp, height = 76.dp) 69 | .padding(20.dp) 70 | .clip(CircleShape) 71 | 72 | 73 | @Composable 74 | fun HomeScreen( 75 | state: HomeStatePort, 76 | modifier: Modifier = Modifier, 77 | dispatcher: CoroutineDispatcher = Dispatchers.IO, 78 | imageLoader: @Composable (String) -> Resource = { asyncPainterResource(it) }, 79 | onFavoritesClicked: () -> Unit 80 | ) { 81 | 82 | val scope = rememberCoroutineScope() 83 | var favoriteDialogItem: GithubRepositoryStatePort? by remember { mutableStateOf(null) } 84 | 85 | @Composable 86 | fun TopAppBarContent() { 87 | 88 | @Composable 89 | fun FavoritesIconButton() { 90 | IconButton(onClick = { onFavoritesClicked() }) { 91 | Icon( 92 | Icons.Filled.Favorite, 93 | contentDescription = null, 94 | tint = MaterialTheme.colors.background 95 | ) 96 | } 97 | } 98 | 99 | TopAppBar( 100 | title = { Text(text = "Home", modifier = Modifier.fillMaxWidth()) }, 101 | actions = { FavoritesIconButton() } 102 | ) 103 | } 104 | 105 | @Composable 106 | fun ListItemsContent() { 107 | 108 | @Composable 109 | fun ErrorContent() { 110 | 111 | @Composable 112 | fun ErrorText() { 113 | Text( 114 | text = "An error occurred: ${state.error?.message}", 115 | style = MaterialTheme.typography.subtitle1 116 | ) 117 | } 118 | 119 | @Composable 120 | fun ErrorIcon() { 121 | Icon( 122 | Icons.Filled.Warning, 123 | contentDescription = null, 124 | tint = MaterialTheme.colors.error, 125 | modifier = Modifier.size(64.dp) 126 | ) 127 | } 128 | 129 | Column( 130 | modifier = Modifier.fillMaxSize().padding(16.dp), 131 | verticalArrangement = Arrangement.Center, 132 | horizontalAlignment = Alignment.CenterHorizontally 133 | ) { 134 | ErrorIcon() 135 | ErrorText() 136 | } 137 | } 138 | 139 | @Composable 140 | fun EmptyContent() { 141 | Box( 142 | modifier = Modifier.fillMaxSize().padding(16.dp), 143 | contentAlignment = Alignment.Center 144 | ) { 145 | Text(text = "No repositories", style = MaterialTheme.typography.h6) 146 | } 147 | } 148 | 149 | @Composable 150 | fun LoadedContent() { 151 | 152 | @Composable 153 | fun ItemContent(item: GithubRepositoryStatePort) { 154 | 155 | @Composable 156 | fun ItemImageSection() { 157 | 158 | @Composable 159 | fun FetchedImage(painter: Painter) { 160 | Image( 161 | painter = painter, 162 | contentDescription = null, 163 | contentScale = ContentScale.Crop, 164 | modifier = imageModifier 165 | ) 166 | } 167 | 168 | @Composable 169 | fun ErrorImage() { 170 | Icon( 171 | Icons.Sharp.Warning, 172 | tint = MaterialTheme.colors.error, 173 | contentDescription = null, 174 | modifier = imageModifier 175 | ) 176 | } 177 | 178 | when (val resource = imageLoader(item.repository.avatarUrl.orEmpty())) { 179 | is Resource.Loading -> CircularProgressIndicator(modifier = imageProgressModifier) 180 | is Resource.Success -> FetchedImage(resource.value) 181 | is Resource.Failure -> ErrorImage() 182 | } 183 | } 184 | 185 | @Composable 186 | fun RowScope.ItemMiddleSection() { 187 | Column( 188 | modifier = Modifier.fillMaxHeight().weight(10f).padding(8.dp), 189 | horizontalAlignment = Alignment.Start, 190 | verticalArrangement = Arrangement.Top 191 | ) { 192 | Text( 193 | text = item.repository.name.orEmpty(), 194 | style = MaterialTheme.typography.subtitle1 195 | ) 196 | Text( 197 | text = item.repository.ownerName.orEmpty(), 198 | style = MaterialTheme.typography.body2 199 | ) 200 | if (item.isFavorite) Icon( 201 | Icons.Filled.Favorite, 202 | tint = MaterialTheme.colors.primary, 203 | contentDescription = null, 204 | modifier = Modifier.fillMaxHeight() 205 | ) 206 | } 207 | } 208 | 209 | @Composable 210 | fun RowScope.ItemStarsSection() { 211 | 212 | @Composable 213 | fun StarIcon() { 214 | Icon( 215 | Icons.Filled.Star, 216 | contentDescription = null, 217 | tint = MaterialTheme.colors.primary, 218 | modifier = Modifier.size(24.dp) 219 | ) 220 | } 221 | 222 | Column( 223 | modifier = Modifier.fillMaxHeight().weight(3f).padding(4.dp), 224 | horizontalAlignment = Alignment.End, 225 | verticalArrangement = Arrangement.SpaceEvenly 226 | ) { 227 | if (item.progress) CircularProgressIndicator(modifier = Modifier.size(24.dp)) 228 | else StarIcon() 229 | Text( 230 | text = item.repository.stargazersCount.toString(), 231 | style = MaterialTheme.typography.subtitle1 232 | ) 233 | } 234 | } 235 | 236 | Row( 237 | modifier = modifier.height(80.dp) 238 | .padding(4.dp) 239 | .clickable { if (!item.progress) favoriteDialogItem = item }, 240 | verticalAlignment = Alignment.CenterVertically, 241 | ) { 242 | ItemImageSection() 243 | ItemMiddleSection() 244 | ItemStarsSection() 245 | } 246 | Divider() 247 | } 248 | 249 | LazyColumn { 250 | items(items = state.repositories, key = { it.repository.id }) { 251 | ItemContent(item = it) 252 | } 253 | } 254 | } 255 | 256 | when { 257 | state.error != null -> ErrorContent() 258 | state.repositories.isEmpty() -> EmptyContent() 259 | else -> LoadedContent() 260 | } 261 | } 262 | 263 | @Composable 264 | fun FavoritesDialog() { 265 | 266 | @Composable 267 | fun ConfirmButton() { 268 | 269 | suspend fun onConfirmClicked() { 270 | favoriteDialogItem?.apply { 271 | favoriteDialogItem = null 272 | if (isFavorite) removeFromFavorites() else addToFavorites() 273 | } 274 | } 275 | 276 | Button(onClick = { scope.launch(dispatcher) { onConfirmClicked() } }) { 277 | Text(text = if (favoriteDialogItem?.isFavorite == true) "Remove" else "Add") 278 | } 279 | } 280 | 281 | @Composable 282 | fun TextContent() { 283 | Text( 284 | text = "Are you sure you want to " + 285 | "${if (favoriteDialogItem?.isFavorite == true) "remove" else "add"} " + 286 | "repository ${favoriteDialogItem?.repository?.name} to your favorites?" 287 | ) 288 | } 289 | 290 | AlertDialog( 291 | onDismissRequest = { favoriteDialogItem = null }, 292 | title = { Text(text = "Favorites") }, 293 | text = { TextContent() }, 294 | confirmButton = { ConfirmButton() }, 295 | dismissButton = { Button(onClick = { favoriteDialogItem = null }) { Text("Cancel") } } 296 | ) 297 | } 298 | 299 | @Composable 300 | fun HomeScreenContent() { 301 | 302 | LaunchedEffect(Unit) { 303 | withContext(dispatcher) { 304 | state.listAll(dispatcher) { GithubRepositoryState(it) } 305 | } 306 | } 307 | 308 | if (favoriteDialogItem != null) FavoritesDialog() 309 | 310 | Column(modifier = modifier.fillMaxSize()) { 311 | TopAppBarContent() 312 | if (state.progress) LinearProgressIndicator(modifier = Modifier.fillMaxWidth()) 313 | ListItemsContent() 314 | } 315 | } 316 | 317 | HomeScreenContent() 318 | } 319 | --------------------------------------------------------------------------------