├── core
├── di
│ ├── src
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── di
│ │ │ │ └── RemoveThisFile
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── di
│ │ │ │ └── RemoveThisFile
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── di
│ │ │ │ └── RemoveThisFile
│ │ └── commonMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── di
│ │ │ └── CoreDependencyInjection.kt
│ └── build.gradle.kts
├── viewmodels
│ ├── src
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── viewmodels
│ │ │ │ └── RemoveThisFile
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── viewmodels
│ │ │ │ └── RemoveThisFile
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── viewmodels
│ │ │ │ └── RemoveThisFile
│ │ └── commonMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── viewmodels
│ │ │ └── KmmViewModel.kt
│ └── build.gradle.kts
├── common
│ ├── src
│ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── common
│ │ │ │ ├── extensions
│ │ │ │ └── Extensions.kt
│ │ │ │ ├── di
│ │ │ │ └── KoinModuleLoader.kt
│ │ │ │ └── Platform.kt
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── common
│ │ │ │ └── Platform.jvm.kt
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── core
│ │ │ │ └── common
│ │ │ │ └── Platform.ios.kt
│ │ └── androidMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── common
│ │ │ └── Platform.android.kt
│ └── build.gradle.kts
└── ui
│ ├── src
│ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── ui
│ │ │ └── theme
│ │ │ └── Theme.android.kt
│ ├── jvmMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── ui
│ │ │ └── theme
│ │ │ └── Theme.jvm.kt
│ ├── iosMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── core
│ │ │ └── ui
│ │ │ └── theme
│ │ │ └── Theme.ios.kt
│ └── commonMain
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── afalabarce
│ │ └── mvvmkmmtemplate
│ │ └── core
│ │ └── ui
│ │ └── theme
│ │ ├── Type.kt
│ │ ├── Shapes.kt
│ │ ├── Color.kt
│ │ ├── Theme.kt
│ │ └── Dimens.kt
│ └── build.gradle.kts
├── data
├── models
│ ├── src
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ └── jvmMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── models
│ │ │ └── RemoveThisFile
│ └── build.gradle.kts
├── repository
│ ├── src
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── RemoveThisFile
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── RemoveThisFile
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── RemoveThisFile
│ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ ├── RemoveThisFile
│ │ │ │ └── di
│ │ │ │ └── DataRepositoryDependencyInjector.kt
│ │ ├── iosTest
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── DataSourceRepositoryExampleTest.ios.kt
│ │ ├── jvmTest
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── DataSourceRepositoryExampleTest.jvm.kt
│ │ ├── commonTest
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── repository
│ │ │ │ └── DataSourceRepositoryExampleTest.kt
│ │ └── androidUnitTest
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── repository
│ │ │ └── DataSourceRepositoryExampleTest.android.kt
│ └── build.gradle.kts
├── datasources
│ ├── src
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── datasources
│ │ │ │ └── RemoveThisFile
│ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── datasources
│ │ │ │ ├── RemoveThisFile
│ │ │ │ └── features
│ │ │ │ └── preferences
│ │ │ │ └── AppPreferences.kt
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── datasources
│ │ │ │ └── RemoveThisFile
│ │ └── jvmMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── RemoveThisFile
│ └── build.gradle.kts
└── datasources-core
│ ├── src
│ ├── androidMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ ├── RemoveThisFile
│ │ │ ├── features
│ │ │ └── preferences
│ │ │ │ └── DataStoreInstance.android.kt
│ │ │ ├── di
│ │ │ └── DataSourceCoreDependencyInjector.android.kt
│ │ │ └── db
│ │ │ └── DriverFactory.android.kt
│ ├── commonMain
│ │ ├── kotlin
│ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── data
│ │ │ │ └── datasources
│ │ │ │ └── core
│ │ │ │ ├── RemoveThisFile
│ │ │ │ ├── features
│ │ │ │ ├── example
│ │ │ │ │ ├── local
│ │ │ │ │ │ └── model
│ │ │ │ │ │ │ └── ExampleEntity.kt
│ │ │ │ │ └── remote
│ │ │ │ │ │ └── RemoteExampleEntity.kt
│ │ │ │ └── preferences
│ │ │ │ │ ├── DataStoreInstance.kt
│ │ │ │ │ └── AppPreferencesImpl.kt
│ │ │ │ ├── db
│ │ │ │ ├── DriverFactory.kt
│ │ │ │ └── Database.kt
│ │ │ │ ├── remote
│ │ │ │ └── ApiService.kt
│ │ │ │ └── di
│ │ │ │ └── DataSourceCoreDependencyInjector.kt
│ │ └── sqldelight
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ └── db
│ │ │ └── MvvmKmmTemplate.sq
│ ├── iosMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ ├── RemoveThisFile
│ │ │ ├── db
│ │ │ └── DriverFactory.ios.kt
│ │ │ ├── di
│ │ │ └── DataSourceCoreDependencyInjector.ios.kt
│ │ │ └── features
│ │ │ └── preferences
│ │ │ └── DataStoreInstance.ios.kt
│ ├── jvmMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ ├── RemoveThisFile
│ │ │ ├── db
│ │ │ └── DriverFactory.jvm.kt
│ │ │ ├── di
│ │ │ └── DataSourceCoreDependencyInjector.jvm.kt
│ │ │ └── features
│ │ │ └── preferences
│ │ │ └── DataStoreInstance.jvm.kt
│ ├── commonTest
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ └── DataSourceCoreExampleTest.kt
│ ├── iosTest
│ │ └── kotlin
│ │ │ └── DataSourceCoreExampleTest.ios.kt
│ ├── jvmTest
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── data
│ │ │ └── datasources
│ │ │ └── core
│ │ │ └── DataSourceCoreExampleTest.jvm.kt
│ └── androidUnitTest
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── afalabarce
│ │ └── mvvmkmmtemplate
│ │ └── data
│ │ └── datasources
│ │ └── core
│ │ └── DataSourceCoreExampleTest.android.kt
│ └── build.gradle.kts
├── domain
├── models
│ ├── src
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── models
│ │ │ │ └── RemoveThisFile
│ │ └── commonMain
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── domain
│ │ │ └── models
│ │ │ └── RemoveThisFile
│ └── build.gradle.kts
├── usecases
│ ├── src
│ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ └── RemoveThisFile
│ │ ├── jvmMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ └── RemoveThisFile
│ │ ├── androidMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ └── RemoveThisFile
│ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ ├── RemoveThisFile
│ │ │ │ └── di
│ │ │ │ └── DomainUseCaseDependencyInjector.kt
│ │ ├── iosTest
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ └── Test.ios.kt
│ │ ├── commonTest
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── domain
│ │ │ │ └── usecases
│ │ │ │ └── Test.kt
│ │ └── androidUnitTest
│ │ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── domain
│ │ │ └── usecases
│ │ │ └── Test.android.kt
│ └── build.gradle.kts
└── repository
│ └── build.gradle.kts
├── presentation
├── ui
│ ├── src
│ │ ├── iosMain
│ │ │ ├── kotlin
│ │ │ │ ├── io
│ │ │ │ │ └── github
│ │ │ │ │ │ └── afalabarce
│ │ │ │ │ │ └── mvvmkmmtemplate
│ │ │ │ │ │ └── presentation
│ │ │ │ │ │ └── ui
│ │ │ │ │ │ └── RemoveMe
│ │ │ │ └── main.kt
│ │ │ └── libres
│ │ │ │ └── images
│ │ │ │ └── ic_launcher_icns.icns
│ │ ├── jvmMain
│ │ │ ├── libres
│ │ │ │ └── images
│ │ │ │ │ └── ic_launcher_ico.ico
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── presentation
│ │ │ │ └── ui
│ │ │ │ └── main.kt
│ │ ├── commonMain
│ │ │ ├── libres
│ │ │ │ └── images
│ │ │ │ │ └── ic_launcher_(orig).png
│ │ │ └── kotlin
│ │ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── presentation
│ │ │ │ └── ui
│ │ │ │ ├── di
│ │ │ │ └── PresentationUiDependencyInjector.kt
│ │ │ │ └── App.kt
│ │ └── androidMain
│ │ │ ├── kotlin
│ │ │ └── io
│ │ │ │ └── github
│ │ │ │ └── afalabarce
│ │ │ │ └── mvvmkmmtemplate
│ │ │ │ └── presentation
│ │ │ │ └── ui
│ │ │ │ ├── App.android.kt
│ │ │ │ └── CustomAndroidApp.kt
│ │ │ └── AndroidManifest.xml
│ ├── webpack.config.d
│ │ └── config.js
│ └── build.gradle.kts
└── viewmodels
│ ├── src
│ ├── iosMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── RemoveThisFile
│ ├── jvmMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── RemoveThisFile
│ ├── androidMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── RemoveThisFile
│ ├── commonMain
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ ├── RemoveThisFile
│ │ │ └── di
│ │ │ └── PresentationViewModelsDependencyInjector.kt
│ ├── commonTest
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── PresentationViewModelsExampleTest.kt
│ ├── iosTest
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── PresentationViewModelsExampleTest.ios.kt
│ ├── jvmTest
│ │ └── kotlin
│ │ │ └── io
│ │ │ └── github
│ │ │ └── afalabarce
│ │ │ └── mvvmkmmtemplate
│ │ │ └── presentation
│ │ │ └── viewmodels
│ │ │ └── PresentationViewModelsExampleTest.jvm.kt
│ └── androidUnitTest
│ │ └── kotlin
│ │ └── io
│ │ └── github
│ │ └── afalabarce
│ │ └── mvvmkmmtemplate
│ │ └── presentation
│ │ └── viewmodels
│ │ └── PresentationViewModelsExampleTest.android.kt
│ └── build.gradle.kts
├── art
├── kmp_structure.png
├── MVVM_KMM_Template.png
├── app_execution_tasks.png
├── sqldelight_sq_file_path.png
└── MVVM KMM Template.graphml
├── iosApp
├── iosApp
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ └── iosApp.swift
└── iosApp.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ └── project.pbxproj
├── gradle
├── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
└── libs.versions.toml
├── README.MD
├── .gitignore
├── .run
├── iosApp.run.xml
├── jvmApp.run.xml
└── androidApp.run.xml
├── gradle.properties
├── settings.gradle.kts
├── gradlew.bat
└── gradlew
/core/di/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/di/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/di/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/di/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/di/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/di/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/models/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/models/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/models/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/models/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/models/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/models/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/presentation/ui/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/RemoveMe:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/viewmodels/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/viewmodels/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/repository/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/repository/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/repository/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/repository/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/models/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/models/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/models/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/usecases/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/usecases/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/viewmodels/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/repository/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/repository/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/repository/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/repository/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/usecases/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/domain/usecases/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources-core/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources-core/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/data/datasources-core/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/presentation/viewmodels/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/presentation/viewmodels/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/presentation/viewmodels/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/presentation/viewmodels/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/RemoveThisFile:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/art/kmp_structure.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/art/kmp_structure.png
--------------------------------------------------------------------------------
/art/MVVM_KMM_Template.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/art/MVVM_KMM_Template.png
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/art/app_execution_tasks.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/art/app_execution_tasks.png
--------------------------------------------------------------------------------
/art/sqldelight_sq_file_path.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/art/sqldelight_sq_file_path.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # Plantilla MVVM Kotlin MultiPlatform / MVVM Kotlin MultiPlatform Template
2 |
3 | ## [English version](README.EN.MD)
4 |
5 | ## [Versión en Español](README.ES.MD)
6 |
7 |
--------------------------------------------------------------------------------
/core/common/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/extensions/Extensions.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common.extensions
2 |
3 |
--------------------------------------------------------------------------------
/core/ui/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/presentation/ui/src/iosMain/libres/images/ic_launcher_icns.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/presentation/ui/src/iosMain/libres/images/ic_launcher_icns.icns
--------------------------------------------------------------------------------
/presentation/ui/src/jvmMain/libres/images/ic_launcher_ico.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/presentation/ui/src/jvmMain/libres/images/ic_launcher_ico.ico
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | *.iml
3 | .gradle
4 | .idea
5 | .DS_Store
6 | build
7 | */build
8 | captures
9 | .externalNativeBuild
10 | .cxx
11 | local.properties
12 | xcuserdata/
13 | Pods/
14 | *.jks
15 | *yarn.lock
16 |
--------------------------------------------------------------------------------
/presentation/ui/src/commonMain/libres/images/ic_launcher_(orig).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/afalabarce/MVVM-Multiplatform-Layered-Template/HEAD/presentation/ui/src/commonMain/libres/images/ic_launcher_(orig).png
--------------------------------------------------------------------------------
/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 | }
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 |
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/core/ui/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Theme.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.runtime.Composable
4 |
5 | @Composable
6 | actual fun SystemAppearance(isDark: Boolean) {
7 | }
--------------------------------------------------------------------------------
/core/common/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/di/KoinModuleLoader.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common.di
2 |
3 | import org.koin.core.module.Module
4 |
5 | interface KoinModuleLoader {
6 | val koinModules: List
7 | }
--------------------------------------------------------------------------------
/core/common/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/Platform.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common
2 |
3 | interface Platform {
4 | val name: String
5 | }
6 |
7 | expect fun getPlatform(): Platform
8 |
9 | expect fun openUrl(url: String?)
--------------------------------------------------------------------------------
/iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "platform" : "ios",
6 | "size" : "1024x1024"
7 | }
8 | ],
9 | "info" : {
10 | "author" : "xcode",
11 | "version" : 1
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/iosApp/iosApp.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/data/datasources-core/src/commonTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/DataSourceCoreExampleTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | expect class DataSourceCoreExampleTest {
7 | @Test
8 | fun testExample()
9 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/iosTest/kotlin/DataSourceCoreExampleTest.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | actual class DataSourceCoreExampleTest {
7 | @Test
8 | actual fun testExample() {
9 | assertTrue(true, "Check iOS is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/data/datasources/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/features/preferences/AppPreferences.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.features.preferences
2 |
3 | import kotlinx.coroutines.flow.Flow
4 |
5 | interface AppPreferences {
6 | fun getDeviceId(): Flow
7 | suspend fun setDeviceId(deviceId: Long)
8 | }
--------------------------------------------------------------------------------
/domain/usecases/src/iosTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/Test.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.domain.usecases
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class IosGreetingTest {
7 |
8 | @Test
9 | fun testExample() {
10 | assertTrue(true, "Check iOS is mentioned")
11 | }
12 | }
--------------------------------------------------------------------------------
/domain/usecases/src/commonTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/Test.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.domain.usecases
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class CommonGreetingTest {
7 |
8 | @Test
9 | fun testExample() {
10 | assertTrue(true, "Check 'Hello' is mentioned")
11 | }
12 | }
--------------------------------------------------------------------------------
/data/repository/src/iosTest/kotlin/io/afalabarce/mvvmkmmtemplate/data/repository/DataSourceRepositoryExampleTest.ios.kt:
--------------------------------------------------------------------------------
1 | package io.afalabarce.mvvmkmmtemplate.data.repository
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class DataSourceRepositoryExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check iOS is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/data/repository/src/jvmTest/kotlin/io/afalabarce/mvvmkmmtemplate/data/repository/DataSourceRepositoryExampleTest.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.afalabarce.mvvmkmmtemplate.data.repository
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class DataSourceRepositoryExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check JVM is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/domain/usecases/src/androidUnitTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/Test.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.domain.usecases
2 |
3 | import org.junit.Assert.assertTrue
4 | import org.junit.Test
5 |
6 | class AndroidGreetingTest {
7 |
8 | @Test
9 | fun testExample() {
10 | assertTrue("Check Android is mentioned", true)
11 | }
12 | }
--------------------------------------------------------------------------------
/data/repository/src/commonTest/kotlin/io/afalabarce/mvvmkmmtemplate/data/repository/DataSourceRepositoryExampleTest.kt:
--------------------------------------------------------------------------------
1 | package io.afalabarce.mvvmkmmtemplate.data.repository
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class DataSourceRepositoryExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check Common is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/data/repository/src/androidUnitTest/kotlin/io/afalabarce/mvvmkmmtemplate/data/repository/DataSourceRepositoryExampleTest.android.kt:
--------------------------------------------------------------------------------
1 | package io.afalabarce.mvvmkmmtemplate.data.repository
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class DataSourceRepositoryExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check Android is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/jvmTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/DataSourceCoreExampleTest.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | actual class DataSourceCoreExampleTest {
7 | @Test
8 | actual fun testExample() {
9 | assertTrue(true, "Check JVM is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/presentation/viewmodels/src/commonTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/PresentationViewModelsExampleTest.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class PresentationViewModelsExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check Common is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/presentation/viewmodels/src/iosTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/PresentationViewModelsExampleTest.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class PresentationViewModelsExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check iOS is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/presentation/viewmodels/src/jvmTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/PresentationViewModelsExampleTest.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class PresentationViewModelsExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check JVM is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/androidUnitTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/DataSourceCoreExampleTest.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core
2 |
3 | import org.junit.Assert
4 | import org.junit.Test
5 |
6 | actual class DataSourceCoreExampleTest {
7 | @Test
8 | actual fun testExample() {
9 | Assert.assertTrue("Check Android is mentioned", true)
10 | }
11 | }
--------------------------------------------------------------------------------
/data/repository/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/repository/di/DataRepositoryDependencyInjector.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.repository.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
4 | import org.koin.core.module.Module
5 |
6 | object DataRepositoryDependencyInjector: KoinModuleLoader {
7 | override val koinModules: List
8 | get() = listOf()
9 | }
--------------------------------------------------------------------------------
/domain/usecases/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/domain/usecases/di/DomainUseCaseDependencyInjector.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.domain.usecases.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
4 | import org.koin.core.module.Module
5 |
6 | object DomainUseCaseDependencyInjector: KoinModuleLoader {
7 | override val koinModules: List
8 | get() = listOf()
9 | }
--------------------------------------------------------------------------------
/presentation/viewmodels/src/androidUnitTest/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/PresentationViewModelsExampleTest.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class PresentationViewModelsExampleTest {
7 | @Test
8 | fun testExample() {
9 | assertTrue(true, "Check Android is mentioned")
10 | }
11 | }
--------------------------------------------------------------------------------
/presentation/viewmodels/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/viewmodels/di/PresentationViewModelsDependencyInjector.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
4 | import org.koin.core.module.Module
5 |
6 | object PresentationViewModelsDependencyInjector: KoinModuleLoader {
7 | override val koinModules: List
8 | get() = listOf()
9 | }
--------------------------------------------------------------------------------
/.run/iosApp.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/core/common/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/Platform.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common
2 |
3 | import java.awt.Desktop
4 | import java.net.URI
5 |
6 | class JvmPlatform: Platform {
7 | override val name: String = "JvmApp"
8 | }
9 |
10 | actual fun getPlatform(): Platform = JvmPlatform()
11 |
12 | actual fun openUrl(url: String?) {
13 | val uri = url?.let { URI.create(it) } ?: return
14 | Desktop.getDesktop().browse(uri)
15 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/DriverFactory.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 | import app.cash.sqldelight.driver.native.NativeSqliteDriver
5 | actual class DriverFactory {
6 | actual fun createDriver(): SqlDriver {
7 | return NativeSqliteDriver(
8 | KmmDatabase.Schema,
9 | Database.databaseName
10 | )
11 | }
12 | }
--------------------------------------------------------------------------------
/presentation/ui/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/App.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.ui
2 |
3 | import android.os.Bundle
4 | import androidx.activity.ComponentActivity
5 | import androidx.activity.compose.setContent
6 |
7 | class AppActivity : ComponentActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContent {
11 | App()
12 | }
13 | }
14 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 | #Gradle
3 | org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8 -Dkotlin.daemon.jvm.options\="-Xmx2048M"
4 | org.gradle.caching=true
5 | org.gradle.configuration-cache=true
6 | org.gradle.unsafe.configuration-cache=false
7 |
8 | #Kotlin
9 | kotlin.code.style=official
10 | kotlin.js.compiler=ir
11 |
12 | #Compose
13 | org.jetbrains.compose.experimental.uikit.enabled=true
14 | org.jetbrains.compose.experimental.jscanvas.enabled=true
15 |
16 | #Android
17 | android.useAndroidX=true
18 | android.nonTransitiveRClass=true
19 |
--------------------------------------------------------------------------------
/data/datasources-core/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/di/DataSourceCoreDependencyInjector.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences.dataStore
4 | import org.koin.core.module.Module
5 | import org.koin.core.module.dsl.singleOf
6 | import org.koin.dsl.module
7 |
8 | actual fun getPlatformInjects(): List = listOf(
9 | module {
10 | singleOf(::dataStore)
11 | }
12 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/DriverFactory.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 | import app.cash.sqldelight.driver.jdbc.sqlite.JdbcSqliteDriver
5 |
6 | actual class DriverFactory {
7 | actual fun createDriver(): SqlDriver {
8 | val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
9 | KmmDatabase.Schema.create(driver)
10 | return driver
11 | }
12 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/di/DataSourceCoreDependencyInjector.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences.dataStore
4 | import org.koin.core.module.Module
5 | import org.koin.core.module.dsl.singleOf
6 | import org.koin.dsl.module
7 |
8 | actual fun getPlatformInjects(): List = listOf(
9 | module {
10 | singleOf(::dataStore)
11 | }
12 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/preferences/DataStoreInstance.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences
2 |
3 | import android.content.Context
4 | import androidx.datastore.core.DataStore
5 | import androidx.datastore.preferences.core.Preferences
6 |
7 | fun dataStore(context: Context): DataStore =
8 | createDataStore(
9 | producePath = { context.filesDir.resolve(dataStoreFileName).absolutePath }
10 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/example/local/model/ExampleEntity.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.example.local.model
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class ExampleEntity(
8 | @SerialName("id")
9 | val id: Long,
10 | @SerialName("title")
11 | val title: String,
12 | @SerialName("description")
13 | val description: String
14 | )
15 |
--------------------------------------------------------------------------------
/presentation/ui/webpack.config.d/config.js:
--------------------------------------------------------------------------------
1 | const TerserPlugin = require("terser-webpack-plugin");
2 |
3 | config.optimization = config.optimization || {};
4 | config.optimization.minimize = true;
5 | config.optimization.minimizer = [
6 | new TerserPlugin({
7 | terserOptions: {
8 | mangle: true, // Note: By default, mangle is set to true.
9 | compress: false, // Disable the transformations that reduce the code size.
10 | output: {
11 | beautify: false,
12 | },
13 | },
14 | }),
15 | ];
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/DriverFactory.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db
2 |
3 | import app.cash.sqldelight.db.SqlDriver
4 |
5 | expect class DriverFactory {
6 | fun createDriver(): SqlDriver
7 | }
8 |
9 | fun createDatabase(driverFactory: DriverFactory): KmmDatabase {
10 | val driver = driverFactory.createDriver()
11 | val database = KmmDatabase(driver)
12 |
13 | // Do more work with the database (see below).
14 | return database
15 | }
16 |
17 |
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/example/remote/RemoteExampleEntity.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.example.remote
2 |
3 | import kotlinx.serialization.SerialName
4 | import kotlinx.serialization.Serializable
5 |
6 | @Serializable
7 | data class RemoteExampleEntity(
8 | @SerialName("id")
9 | val remoteId: Long,
10 | @SerialName("title")
11 | val remoteTitle: String,
12 | @SerialName("description")
13 | val remoteDescription: String
14 | )
15 |
--------------------------------------------------------------------------------
/presentation/ui/src/iosMain/kotlin/main.kt:
--------------------------------------------------------------------------------
1 | import androidx.compose.ui.window.ComposeUIViewController
2 | import io.github.afalabarce.mvvmkmmtemplate.presentation.ui.App
3 | import io.github.afalabarce.mvvmkmmtemplate.presentation.ui.di.PresentationUiDependencyInjector
4 | import org.koin.core.context.startKoin
5 | import platform.UIKit.UIViewController
6 |
7 | fun MainViewController(): UIViewController = ComposeUIViewController { App() }
8 |
9 | fun initKoin(){
10 | startKoin{
11 | modules(
12 | PresentationUiDependencyInjector.koinModules
13 | )
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/data/datasources-core/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/preferences/DataStoreInstance.jvm.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.Preferences
5 | import java.io.File
6 |
7 | fun dataStore(): DataStore = createDataStore(
8 | producePath = {
9 | val documentDirectory: String? = System.getProperty("user.dir")
10 |
11 | requireNotNull(documentDirectory) + "${File.separator}$dataStoreFileName"
12 | }
13 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/remote/ApiService.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.remote
2 |
3 | import de.jensklingenberg.ktorfit.http.Body
4 | import de.jensklingenberg.ktorfit.http.GET
5 | import de.jensklingenberg.ktorfit.http.POST
6 |
7 | interface ApiService {
8 | @GET("/api/values")
9 | suspend fun getAllItems(): List
10 |
11 | @POST("/api/values")
12 | suspend fun putAllItems(@Body items: List)
13 | companion object {
14 | const val API_URL = "https://your.own.api"
15 | }
16 | }
--------------------------------------------------------------------------------
/core/common/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/Platform.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common
2 |
3 | import platform.Foundation.NSURL
4 | import platform.UIKit.UIApplication
5 | import platform.UIKit.UIDevice
6 |
7 | class IOSPlatform: Platform {
8 | override val name: String = UIDevice.currentDevice.systemName() + " " + UIDevice.currentDevice.systemVersion
9 | }
10 |
11 | actual fun getPlatform(): Platform = IOSPlatform()
12 |
13 | actual fun openUrl(url: String?) {
14 | val nsUrl = url?.let { NSURL.URLWithString(it) } ?: return
15 | UIApplication.sharedApplication.openURL(nsUrl)
16 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/di/DataSourceCoreDependencyInjector.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences.dataStore
4 | import org.koin.android.ext.koin.androidContext
5 | import org.koin.core.module.Module
6 | import org.koin.core.module.dsl.singleOf
7 | import org.koin.dsl.module
8 |
9 | actual fun getPlatformInjects(): List = listOf(
10 | module {
11 | factory { androidContext() }
12 | singleOf(::dataStore)
13 | }
14 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/sqldelight/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/MvvmKmmTemplate.sq:
--------------------------------------------------------------------------------
1 | CREATE TABLE table_example (
2 | id INTEGER PRIMARY KEY AUTOINCREMENT,
3 | title TEXT NOT NULL DEFAULT '',
4 | description TEXT NOT NULL DEFAULT ''
5 | );
6 |
7 | selectAll:
8 | SELECT * FROM table_example;
9 |
10 | insertItem:
11 | INSERT INTO table_example(title,description)
12 | VALUES (?, ?);
13 |
14 | updateItem:
15 | UPDATE table_example SET title = ?, description = ? WHERE id = ?;
16 |
17 | deleteById:
18 | DELETE FROM table_example WHERE id = ?;
19 |
20 | deleteAll:
21 | DELETE FROM table_example;
22 |
23 |
--------------------------------------------------------------------------------
/iosApp/iosApp/iosApp.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import SwiftUI
3 | import presentationUi
4 |
5 | @main
6 | struct iosApp: App {
7 | var body: some Scene {
8 | WindowGroup {
9 | ContentView()
10 | }
11 | }
12 | }
13 |
14 | struct ContentView: View {
15 | var body: some View {
16 | ComposeView().ignoresSafeArea(.all)
17 | }
18 | }
19 |
20 | struct ComposeView: UIViewControllerRepresentable {
21 | func makeUIViewController(context: Context) -> UIViewController {
22 | //MainKt.initKoin()
23 | MainKt.MainViewController()
24 | }
25 |
26 | func updateUIViewController(_ uiViewController: UIViewController, context: Context) {}
27 | }
28 |
--------------------------------------------------------------------------------
/data/datasources-core/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/DriverFactory.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db
2 |
3 | import android.content.Context
4 | import app.cash.sqldelight.db.SqlDriver
5 | import app.cash.sqldelight.driver.android.AndroidSqliteDriver
6 | import org.koin.java.KoinJavaComponent.inject
7 |
8 | actual class DriverFactory {
9 | private val context: Context by inject(Context::class.java)
10 | actual fun createDriver(): SqlDriver {
11 | return AndroidSqliteDriver(
12 | KmmDatabase.Schema,
13 | this.context,
14 | Database.databaseName)
15 | }
16 | }
--------------------------------------------------------------------------------
/core/ui/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Theme.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.runtime.Composable
4 | import androidx.compose.runtime.LaunchedEffect
5 | import platform.UIKit.UIApplication
6 | import platform.UIKit.UIStatusBarStyleDarkContent
7 | import platform.UIKit.UIStatusBarStyleLightContent
8 | import platform.UIKit.setStatusBarStyle
9 |
10 | @Composable
11 | actual fun SystemAppearance(isDark: Boolean) {
12 | LaunchedEffect(isDark) {
13 | UIApplication.sharedApplication.setStatusBarStyle(
14 | if (isDark) UIStatusBarStyleDarkContent else UIStatusBarStyleLightContent
15 | )
16 | }
17 | }
--------------------------------------------------------------------------------
/presentation/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/di/PresentationUiDependencyInjector.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.ui.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
4 | import io.github.afalabarce.mvvmkmmtemplate.core.di.CoreDependencyInjection
5 | import org.koin.core.module.Module
6 |
7 | object PresentationUiDependencyInjector:KoinModuleLoader {
8 | override val koinModules: List
9 | get() = listOf(
10 | CoreDependencyInjection.koinModules,
11 | listOf(
12 | // TODO Add all presentation ui dependencies, if needed
13 | )
14 | ).flatten()
15 |
16 | }
--------------------------------------------------------------------------------
/presentation/ui/src/jvmMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/main.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.ui
2 |
3 | import androidx.compose.ui.unit.dp
4 | import androidx.compose.ui.window.Window
5 | import androidx.compose.ui.window.application
6 | import androidx.compose.ui.window.rememberWindowState
7 | import java.awt.Dimension
8 | import io.github.afalabarce.mvvmkmmtemplate.presentation.ui.App
9 |
10 | fun main() = application {
11 | Window(
12 | title = "MVVM Multiplatform Template",
13 | state = rememberWindowState(width = 800.dp, height = 600.dp),
14 | onCloseRequest = ::exitApplication,
15 | ) {
16 | window.minimumSize = Dimension(350, 600)
17 | App()
18 | }
19 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/preferences/DataStoreInstance.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.PreferenceDataStoreFactory
5 | import androidx.datastore.preferences.core.Preferences
6 | import okio.Path.Companion.toPath
7 |
8 | fun createDataStore(
9 | producePath: () -> String,
10 | ): DataStore = PreferenceDataStoreFactory.createWithPath(
11 | corruptionHandler = null,
12 | migrations = emptyList(),
13 | produceFile = { producePath().toPath() },
14 | )
15 |
16 | internal const val dataStoreFileName = "mvvmkmmtemplate.preferences_pb"
--------------------------------------------------------------------------------
/presentation/ui/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/CustomAndroidApp.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.ui
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.AndroidApp
4 | import io.github.afalabarce.mvvmkmmtemplate.presentation.ui.di.PresentationUiDependencyInjector
5 | import org.koin.android.ext.koin.androidContext
6 | import org.koin.core.context.GlobalContext.startKoin
7 |
8 | class CustomAndroidApp: AndroidApp() {
9 | override fun onCreate() {
10 | startKoin {
11 | androidContext(this@CustomAndroidApp)
12 | // androidModule: refers to Android-specific dependencies
13 | // appModule: refers to Shared module dependencies
14 | modules(
15 | PresentationUiDependencyInjector.koinModules
16 | )
17 | }
18 | super.onCreate()
19 | }
20 | }
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | @file:Suppress("UnstableApiUsage")
2 |
3 | rootProject.name = "MVVM-Multiplatform-Layered-Template"
4 |
5 | pluginManagement {
6 | repositories {
7 | google()
8 | gradlePluginPortal()
9 | mavenCentral()
10 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
11 | }
12 | }
13 |
14 | dependencyResolutionManagement {
15 | repositories {
16 | google()
17 | mavenCentral()
18 | maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
19 | }
20 | }
21 |
22 | include(":presentation:ui")
23 | include(":presentation:viewmodels")
24 | include(":core:ui")
25 | include(":core:common")
26 | include(":core:di")
27 | include(":core:viewmodels")
28 | include(":domain:usecases")
29 | include(":domain:repository")
30 | include(":domain:models")
31 | include(":data:datasources-core")
32 | include(":data:repository")
33 | include(":data:datasources")
34 | include(":data:models")
--------------------------------------------------------------------------------
/core/common/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/common/Platform.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.common
2 |
3 | import android.app.Application
4 | import android.content.Intent
5 | import android.net.Uri
6 |
7 | class AndroidPlatform : Platform {
8 | override val name: String = "Android ${android.os.Build.VERSION.SDK_INT}"
9 | }
10 |
11 | open class AndroidApp : Application() {
12 | companion object {
13 | lateinit var INSTANCE: AndroidApp
14 | }
15 |
16 | override fun onCreate() {
17 | super.onCreate()
18 | INSTANCE = this
19 | }
20 | }
21 |
22 | actual fun getPlatform(): Platform = AndroidPlatform()
23 |
24 | actual fun openUrl(url: String?) {
25 | val uri = url?.let { Uri.parse(it) } ?: return
26 | val intent = Intent().apply {
27 | action = Intent.ACTION_VIEW
28 | data = uri
29 | addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
30 | }
31 | AndroidApp.INSTANCE.startActivity(intent)
32 | }
--------------------------------------------------------------------------------
/core/ui/src/androidMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Theme.android.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import android.app.Activity
4 | import android.graphics.Color
5 | import androidx.compose.runtime.Composable
6 | import androidx.compose.runtime.LaunchedEffect
7 | import androidx.compose.ui.platform.LocalView
8 | import androidx.core.view.WindowCompat
9 |
10 | @Composable
11 | actual fun SystemAppearance(isDark: Boolean) {
12 | val view = LocalView.current
13 | val systemBarColor = Color.TRANSPARENT
14 | LaunchedEffect(isDark) {
15 | val window = (view.context as Activity).window
16 | WindowCompat.setDecorFitsSystemWindows(window, false)
17 | window.statusBarColor = systemBarColor
18 | window.navigationBarColor = systemBarColor
19 | WindowCompat.getInsetsController(window, window.decorView).apply {
20 | isAppearanceLightStatusBars = isDark
21 | isAppearanceLightNavigationBars = isDark
22 | }
23 | }
24 | }
--------------------------------------------------------------------------------
/presentation/ui/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.run/jvmApp.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
16 |
17 |
18 | true
19 | true
20 | false
21 | false
22 |
23 |
24 |
--------------------------------------------------------------------------------
/core/di/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/di/CoreDependencyInjection.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.di
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
4 | import io.github.afalabarce.mvvmkmmtemplate.data.repository.di.DataRepositoryDependencyInjector
5 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.di.DataSourceCoreDependencyInjector
6 | import io.github.afalabarce.mvvmkmmtemplate.domain.usecases.di.DomainUseCaseDependencyInjector
7 | import io.github.afalabarce.mvvmkmmtemplate.presentation.viewmodels.di.PresentationViewModelsDependencyInjector
8 | import org.koin.core.module.Module
9 |
10 | object CoreDependencyInjection : KoinModuleLoader{
11 | override val koinModules: List
12 | get() =
13 | listOf(
14 | DataSourceCoreDependencyInjector.koinModules,
15 | DataRepositoryDependencyInjector.koinModules,
16 | DomainUseCaseDependencyInjector.koinModules,
17 | PresentationViewModelsDependencyInjector.koinModules,
18 | ).flatten()
19 |
20 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/iosMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/preferences/DataStoreInstance.ios.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.Preferences
5 | import io.ktor.http.ContentDisposition.Companion.File
6 | import kotlinx.cinterop.ExperimentalForeignApi
7 | import platform.Foundation.NSDocumentDirectory
8 | import platform.Foundation.NSFileManager
9 | import platform.Foundation.NSURL
10 | import platform.Foundation.NSUserDomainMask
11 |
12 | @OptIn(ExperimentalForeignApi::class)
13 | fun dataStore(): DataStore = createDataStore(
14 | producePath = {
15 | val documentDirectory: NSURL? = NSFileManager.defaultManager.URLForDirectory(
16 | directory = NSDocumentDirectory,
17 | inDomain = NSUserDomainMask,
18 | appropriateForURL = null,
19 | create = false,
20 | error = null,
21 | )
22 | requireNotNull(documentDirectory).path + "/$dataStoreFileName"
23 | }
24 | )
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/features/preferences/AppPreferencesImpl.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences
2 |
3 | import androidx.datastore.core.DataStore
4 | import androidx.datastore.preferences.core.Preferences
5 | import androidx.datastore.preferences.core.edit
6 | import androidx.datastore.preferences.core.longPreferencesKey
7 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.features.preferences.AppPreferences
8 | import kotlinx.coroutines.flow.Flow
9 | import kotlinx.coroutines.flow.map
10 |
11 | class AppPreferencesImpl(
12 | private val dataStore: DataStore
13 | ): AppPreferences {
14 | override fun getDeviceId(): Flow = dataStore.data.map { preferences ->
15 | preferences[DEVICE_ID_KEY] ?: 0
16 | }
17 |
18 | override suspend fun setDeviceId(deviceId: Long) {
19 | dataStore.edit { preferences ->
20 | preferences[DEVICE_ID_KEY] = deviceId
21 | }
22 | }
23 |
24 | companion object {
25 | private val DEVICE_ID_KEY = longPreferencesKey("DeviceId")
26 | }
27 | }
--------------------------------------------------------------------------------
/core/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Type.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.material3.Typography
4 | import androidx.compose.ui.text.TextStyle
5 | import androidx.compose.ui.text.font.FontFamily
6 | import androidx.compose.ui.text.font.FontWeight
7 | import androidx.compose.ui.unit.sp
8 |
9 | // Set of Material typography styles to start with
10 | val Typography = Typography(
11 | bodyLarge = TextStyle(
12 | fontFamily = FontFamily.Default,
13 | fontWeight = FontWeight.Normal,
14 | fontSize = 16.sp,
15 | lineHeight = 24.sp,
16 | letterSpacing = 0.5.sp
17 | ),
18 | bodyMedium = TextStyle(
19 | fontFamily = FontFamily.Default,
20 | fontWeight = FontWeight.Medium,
21 | fontSize = 16.sp
22 | )
23 | /* Other default text styles to override
24 | titleLarge = TextStyle(
25 | fontFamily = FontFamily.Default,
26 | fontWeight = FontWeight.Normal,
27 | fontSize = 22.sp,
28 | lineHeight = 28.sp,
29 | letterSpacing = 0.sp
30 | ),
31 | labelSmall = TextStyle(
32 | fontFamily = FontFamily.Default,
33 | fontWeight = FontWeight.Medium,
34 | fontSize = 11.sp,
35 | lineHeight = 16.sp,
36 | letterSpacing = 0.5.sp
37 | )
38 | */
39 | )
--------------------------------------------------------------------------------
/core/viewmodels/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/viewmodels/KmmViewModel.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.viewmodels
2 |
3 | import dev.icerock.moko.mvvm.viewmodel.ViewModel
4 | import io.github.aakira.napier.Napier
5 | import kotlinx.coroutines.CoroutineExceptionHandler
6 | import kotlinx.coroutines.CoroutineScope
7 | import kotlinx.coroutines.Dispatchers
8 | import kotlinx.coroutines.Job
9 | import kotlinx.coroutines.launch
10 | import kotlinx.coroutines.withContext
11 | import kotlin.coroutines.CoroutineContext
12 |
13 | class KmmViewModel: ViewModel() {
14 | fun CoroutineScope.safeLaunch(
15 | onStart: () -> Unit,
16 | onFinish:() -> Unit,
17 | onError: (Throwable) -> Unit,
18 | onStartContext: CoroutineContext = Dispatchers.Main,
19 | onFinishContext: CoroutineContext = Dispatchers.Main,
20 | launchBody: suspend () -> Unit
21 | ): Job {
22 | val coroutineExceptionHandler = CoroutineExceptionHandler { _, throwable ->
23 | Napier.d(
24 | message = "KmmViewModel coroutine error",
25 | throwable = throwable
26 | )
27 | onError(throwable)
28 | }
29 |
30 | return this.launch(
31 | coroutineExceptionHandler
32 | ) {
33 | withContext(onStartContext) { onStart() }
34 | launchBody()
35 | withContext(onFinishContext) { onFinish() }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/di/DataSourceCoreDependencyInjector.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.di
2 |
3 | import de.jensklingenberg.ktorfit.Ktorfit
4 | import io.github.afalabarce.mvvmkmmtemplate.core.common.di.KoinModuleLoader
5 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db.Database
6 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db.DriverFactory
7 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.preferences.AppPreferencesImpl
8 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.remote.ApiService
9 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.features.preferences.AppPreferences
10 | import org.koin.core.module.Module
11 | import org.koin.core.module.dsl.singleOf
12 | import org.koin.dsl.module
13 |
14 | expect fun getPlatformInjects(): List
15 |
16 | object DataSourceCoreDependencyInjector: KoinModuleLoader {
17 | override val koinModules: List
18 | get() = getPlatformInjects().union(
19 | listOf(
20 | module {
21 | single {
22 | Ktorfit
23 | .Builder()
24 | .baseUrl(ApiService.API_URL)
25 | .build()
26 | .create()
27 | }
28 | singleOf(::Database)
29 | single{ AppPreferencesImpl(get()) }
30 | }
31 | )
32 | ).toList()
33 | }
--------------------------------------------------------------------------------
/core/common/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.buildConfig)
5 | alias(libs.plugins.kotlinx.serialization)
6 | alias(libs.plugins.com.google.ksp)
7 | }
8 |
9 | kotlin {
10 | androidTarget {
11 | compilations.all {
12 | kotlinOptions {
13 | jvmTarget = BuildVersion.environment.jvmTarget
14 | }
15 | }
16 | }
17 |
18 | jvm()
19 |
20 | listOf(
21 | iosX64(),
22 | iosArm64(),
23 | iosSimulatorArm64()
24 | ).forEach {
25 | it.binaries.framework {
26 | baseName = "coreCommon"
27 | isStatic = true
28 | }
29 | }
30 |
31 | sourceSets {
32 | commonMain.dependencies {
33 | implementation(libs.bundles.layer.core.common)
34 | }
35 |
36 | commonTest.dependencies {
37 | implementation(kotlin("test"))
38 | }
39 |
40 | androidMain.dependencies {
41 | implementation(libs.bundles.android.core)
42 |
43 | }
44 |
45 | jvmMain.dependencies {
46 | }
47 |
48 | iosMain.dependencies {
49 |
50 | }
51 | }
52 | }
53 |
54 | android {
55 | namespace = "${BuildVersion.environment.applicationId}.core.common"
56 | compileSdk = BuildVersion.android.compileSdk
57 | defaultConfig {
58 | minSdk = BuildVersion.android.minSdk
59 | }
60 |
61 | sourceSets["main"].apply {
62 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
63 | res.srcDirs("src/androidMain/resources")
64 | }
65 | compileOptions {
66 | sourceCompatibility = BuildVersion.environment.javaVersion
67 | targetCompatibility = BuildVersion.environment.javaVersion
68 | }
69 | }
--------------------------------------------------------------------------------
/data/datasources-core/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/data/datasources/core/db/Database.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.db
2 |
3 | import io.github.afalabarce.mvvmkmmtemplate.data.datasources.core.features.example.local.model.ExampleEntity
4 |
5 | class Database(databaseFactory: DriverFactory) {
6 | private val database = KmmDatabase(databaseFactory.createDriver())
7 | private val dbQuery = database.mvvmKmmTemplateQueries
8 |
9 | internal fun clearDatabase() {
10 | dbQuery.transaction {
11 | dbQuery.deleteAll()
12 | }
13 | }
14 |
15 | internal fun deleteById(id: Long) {
16 | dbQuery.transaction {
17 | dbQuery.deleteById(id)
18 | }
19 | }
20 |
21 | internal fun getAllEntities(): List {
22 | return dbQuery.selectAll(::exampleEntityMapper).executeAsList()
23 | }
24 |
25 | internal fun insertOrUpdateEntities(vararg entities: ExampleEntity){
26 | dbQuery.transaction {
27 | entities.forEach { entity ->
28 | if (entity.id == 0L) {
29 | dbQuery.insertItem(
30 | entity.title,
31 | entity.description
32 | )
33 | } else {
34 | dbQuery.updateItem(
35 | entity.title,
36 | entity.description,
37 | entity.id
38 | )
39 | }
40 | }
41 | }
42 | }
43 |
44 | private fun exampleEntityMapper(
45 | id: Long,
46 | title: String,
47 | description: String
48 | ): ExampleEntity = ExampleEntity(
49 | id = id,
50 | title = title,
51 | description = description
52 | )
53 |
54 | companion object {
55 | val databaseName = "KmmDatabase"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/core/viewmodels/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "core.viewmodels"
28 | isStatic = true
29 | }
30 | }
31 |
32 |
33 | sourceSets {
34 | commonMain.dependencies {
35 | implementation(project(mapOf("path" to ":core:common")))
36 | implementation(libs.bundles.layer.core.viewmodels)
37 | }
38 |
39 | commonTest.dependencies {
40 | implementation(kotlin("test"))
41 | }
42 |
43 | androidMain.dependencies {
44 | implementation(libs.bundles.android.core)
45 | }
46 |
47 | jvmMain.dependencies {
48 | }
49 |
50 | iosMain.dependencies {
51 |
52 | }
53 | }
54 | }
55 |
56 | android {
57 | namespace = "${BuildVersion.environment.applicationId}.core.viewmodels"
58 | compileSdk = BuildVersion.android.compileSdk
59 | defaultConfig {
60 | minSdk = BuildVersion.android.minSdk
61 | }
62 |
63 | sourceSets["main"].apply {
64 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
65 | res.srcDirs("src/androidMain/resources")
66 | }
67 | compileOptions {
68 | sourceCompatibility = BuildVersion.environment.javaVersion
69 | targetCompatibility = BuildVersion.environment.javaVersion
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/core/di/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "core.di"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(project(mapOf("path" to ":data:datasources-core")))
36 | implementation(project(mapOf("path" to ":data:repository")))
37 | implementation(project(mapOf("path" to ":domain:usecases")))
38 | implementation(project(mapOf("path" to ":presentation:viewmodels")))
39 | implementation(libs.bundles.layer.core.common)
40 | }
41 |
42 | androidMain.dependencies {
43 | implementation(libs.bundles.android.core)
44 | }
45 |
46 | jvmMain.dependencies {
47 | }
48 |
49 | iosMain.dependencies {
50 |
51 | }
52 | }
53 | }
54 |
55 | android {
56 | namespace = "${BuildVersion.environment.applicationId}.core.di"
57 | compileSdk = BuildVersion.android.compileSdk
58 | defaultConfig {
59 | minSdk = BuildVersion.android.minSdk
60 | }
61 |
62 | sourceSets["main"].apply {
63 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
64 | res.srcDirs("src/androidMain/resources")
65 | }
66 | compileOptions {
67 | sourceCompatibility = BuildVersion.environment.javaVersion
68 | targetCompatibility = BuildVersion.environment.javaVersion
69 | }
70 | }
--------------------------------------------------------------------------------
/data/models/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "data.models"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(libs.bundles.layer.core.common)
36 | }
37 |
38 | commonTest.dependencies {
39 | implementation(kotlin("test"))
40 | }
41 |
42 | androidMain.dependencies {
43 | implementation(libs.bundles.android.core)
44 | }
45 |
46 | jvmMain.dependencies {
47 | }
48 |
49 | iosMain.dependencies {
50 | }
51 | }
52 | }
53 |
54 |
55 | android {
56 | namespace = "${BuildVersion.environment.applicationId}.data.models"
57 | compileSdk = BuildVersion.android.compileSdk
58 | defaultConfig {
59 | minSdk = BuildVersion.android.minSdk
60 | }
61 |
62 | sourceSets["main"].apply {
63 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
64 | res.srcDirs("src/androidMain/resources")
65 | }
66 | compileOptions {
67 | sourceCompatibility = BuildVersion.environment.javaVersion
68 | targetCompatibility = BuildVersion.environment.javaVersion
69 | }
70 | }
71 |
72 | libres {
73 | // https://github.com/Skeptick/libres#setup
74 | }
75 |
76 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
77 |
78 | buildConfig {
79 | // BuildConfig configuration here.
80 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
81 | }
--------------------------------------------------------------------------------
/domain/models/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "domain.models"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(libs.bundles.layer.core.common)
36 | }
37 |
38 | commonTest.dependencies {
39 | implementation(kotlin("test"))
40 | }
41 |
42 | androidMain.dependencies {
43 | implementation(libs.bundles.android.core)
44 | }
45 |
46 | jvmMain.dependencies {
47 | }
48 |
49 | iosMain.dependencies {
50 | }
51 | }
52 | }
53 |
54 |
55 | android {
56 | namespace = "${BuildVersion.environment.applicationId}.domain.models"
57 | compileSdk = BuildVersion.android.compileSdk
58 | defaultConfig {
59 | minSdk = BuildVersion.android.minSdk
60 | }
61 |
62 | sourceSets["main"].apply {
63 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
64 | res.srcDirs("src/androidMain/resources")
65 | }
66 | compileOptions {
67 | sourceCompatibility = BuildVersion.environment.javaVersion
68 | targetCompatibility = BuildVersion.environment.javaVersion
69 | }
70 | }
71 |
72 | libres {
73 | // https://github.com/Skeptick/libres#setup
74 | }
75 |
76 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
77 |
78 | buildConfig {
79 | // BuildConfig configuration here.
80 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
81 | }
--------------------------------------------------------------------------------
/data/datasources/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "dataDatasources"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(project(mapOf("path" to ":data:models")))
36 | implementation(libs.bundles.layer.core.common)
37 | }
38 |
39 | commonTest.dependencies {
40 | implementation(kotlin("test"))
41 | }
42 |
43 | androidMain.dependencies {
44 | implementation(libs.bundles.android.core)
45 | }
46 |
47 | jvmMain.dependencies {
48 | }
49 |
50 | iosMain.dependencies {
51 | }
52 | }
53 | }
54 |
55 | android {
56 | namespace = "${BuildVersion.environment.applicationId}.data.datasources"
57 | compileSdk = BuildVersion.android.compileSdk
58 | defaultConfig {
59 | minSdk = BuildVersion.android.minSdk
60 | }
61 |
62 | sourceSets["main"].apply {
63 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
64 | res.srcDirs("src/androidMain/resources")
65 | }
66 | compileOptions {
67 | sourceCompatibility = BuildVersion.environment.javaVersion
68 | targetCompatibility = BuildVersion.environment.javaVersion
69 | }
70 | }
71 |
72 | libres {
73 | // https://github.com/Skeptick/libres#setup
74 | }
75 |
76 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
77 |
78 | buildConfig {
79 | // BuildConfig configuration here.
80 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
81 | }
--------------------------------------------------------------------------------
/domain/repository/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "domain.repository"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(project(mapOf("path" to ":domain:models")))
36 | implementation(libs.bundles.layer.core.common)
37 | }
38 |
39 | commonTest.dependencies {
40 | implementation(kotlin("test"))
41 | }
42 |
43 | androidMain.dependencies {
44 | implementation(libs.bundles.android.core)
45 | }
46 |
47 | jvmMain.dependencies {
48 | }
49 |
50 | iosMain.dependencies {
51 | }
52 |
53 | }
54 | }
55 |
56 | android {
57 | namespace = "${BuildVersion.environment.applicationId}.domain.repository"
58 | compileSdk = BuildVersion.android.compileSdk
59 | defaultConfig {
60 | minSdk = BuildVersion.android.minSdk
61 | }
62 |
63 | sourceSets["main"].apply {
64 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
65 | res.srcDirs("src/androidMain/resources")
66 | }
67 | compileOptions {
68 | sourceCompatibility = BuildVersion.environment.javaVersion
69 | targetCompatibility = BuildVersion.environment.javaVersion
70 | }
71 | }
72 |
73 |
74 | libres {
75 | // https://github.com/Skeptick/libres#setup
76 | }
77 |
78 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
79 |
80 | buildConfig {
81 | // BuildConfig configuration here.
82 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
83 | }
--------------------------------------------------------------------------------
/core/ui/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.compose)
5 | alias(libs.plugins.libres)
6 | alias(libs.plugins.buildConfig)
7 | alias(libs.plugins.kotlinx.serialization)
8 | alias(libs.plugins.com.google.ksp)
9 | }
10 |
11 | kotlin {
12 | androidTarget {
13 | compilations.all {
14 | kotlinOptions {
15 | jvmTarget = BuildVersion.environment.jvmTarget
16 | }
17 | }
18 | }
19 |
20 | jvm()
21 |
22 | listOf(
23 | iosX64(),
24 | iosArm64(),
25 | iosSimulatorArm64()
26 | ).forEach {
27 | it.binaries.framework {
28 | baseName = "core.ui"
29 | isStatic = true
30 | }
31 | }
32 |
33 |
34 | sourceSets {
35 | commonMain.dependencies {
36 | implementation(project(mapOf("path" to ":core:common")))
37 | implementation(compose.runtime)
38 | implementation(compose.material3)
39 | implementation(compose.materialIconsExtended)
40 | implementation(libs.bundles.layer.core.ui)
41 | }
42 |
43 | commonTest.dependencies {
44 | implementation(kotlin("test"))
45 | }
46 |
47 | androidMain.dependencies {
48 | implementation(libs.bundles.android.core.ui)
49 | }
50 |
51 | jvmMain.dependencies {
52 | implementation(compose.desktop.common)
53 | implementation(compose.desktop.currentOs)
54 | }
55 |
56 | iosMain.dependencies {
57 |
58 | }
59 | }
60 | }
61 |
62 | android {
63 | namespace = "${BuildVersion.environment.applicationId}.core.ui"
64 | compileSdk = BuildVersion.android.compileSdk
65 | defaultConfig {
66 | minSdk = BuildVersion.android.minSdk
67 | }
68 |
69 | sourceSets["main"].apply {
70 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
71 | res.srcDirs("src/androidMain/resources")
72 | }
73 | compileOptions {
74 | sourceCompatibility = BuildVersion.environment.javaVersion
75 | targetCompatibility = BuildVersion.environment.javaVersion
76 | }
77 | buildFeatures {
78 | compose = true
79 | }
80 | composeOptions {
81 | kotlinCompilerExtensionVersion = BuildVersion.environment.composeCompilerVersion
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/presentation/viewmodels/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.buildConfig)
5 | alias(libs.plugins.kotlinx.serialization)
6 | alias(libs.plugins.com.google.ksp)
7 | }
8 |
9 | kotlin {
10 | androidTarget {
11 | compilations.all {
12 | kotlinOptions {
13 | jvmTarget = BuildVersion.environment.jvmTarget
14 | }
15 | }
16 | }
17 |
18 | jvm()
19 |
20 | listOf(
21 | iosX64(),
22 | iosArm64(),
23 | iosSimulatorArm64()
24 | ).forEach {
25 | it.binaries.framework {
26 | baseName = "presentation.viewmodels"
27 | isStatic = true
28 | }
29 | }
30 |
31 | sourceSets {
32 | commonMain.dependencies {
33 | implementation(project(mapOf("path" to ":core:common")))
34 | implementation(project(mapOf("path" to ":core:viewmodels")))
35 | implementation(project(mapOf("path" to ":domain:usecases")))
36 | implementation(project(mapOf("path" to ":domain:models")))
37 | implementation(libs.bundles.layer.core.viewmodels)
38 | }
39 |
40 | commonTest.dependencies {
41 | implementation(kotlin("test"))
42 | }
43 |
44 | androidMain.dependencies {
45 | implementation(libs.bundles.android.core)
46 | }
47 |
48 | jvmMain.dependencies {
49 | }
50 |
51 | iosMain.dependencies {
52 | }
53 | }
54 | }
55 |
56 | android {
57 | namespace = "${BuildVersion.environment.applicationId}.presentation.viewmodels"
58 | compileSdk = BuildVersion.android.compileSdk
59 | defaultConfig {
60 | minSdk = BuildVersion.android.minSdk
61 | }
62 |
63 | sourceSets["main"].apply {
64 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
65 | res.srcDirs("src/androidMain/resources")
66 | }
67 | compileOptions {
68 | sourceCompatibility = BuildVersion.environment.javaVersion
69 | targetCompatibility = BuildVersion.environment.javaVersion
70 | }
71 | }
72 |
73 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
74 |
75 | task("testClasses").doLast {
76 | println("This is a dummy testClasses task")
77 | }
78 |
79 | buildConfig {
80 | // BuildConfig configuration here.
81 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
82 | }
83 |
--------------------------------------------------------------------------------
/domain/usecases/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "domain.usecases"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(project(mapOf("path" to ":domain:repository")))
36 | implementation(project(mapOf("path" to ":domain:models")))
37 | implementation(libs.bundles.layer.core.common)
38 | }
39 |
40 | commonTest.dependencies {
41 | implementation(kotlin("test"))
42 | }
43 |
44 | androidMain.dependencies {
45 | implementation(libs.bundles.android.core)
46 | }
47 |
48 | jvmMain.dependencies {
49 | }
50 |
51 | iosMain.dependencies {
52 | }
53 |
54 | }
55 | }
56 |
57 | android {
58 | namespace = "${BuildVersion.environment.applicationId}.domain.usecases"
59 | compileSdk = BuildVersion.android.compileSdk
60 | defaultConfig {
61 | minSdk = BuildVersion.android.minSdk
62 | }
63 |
64 | sourceSets["main"].apply {
65 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
66 | res.srcDirs("src/androidMain/resources")
67 | }
68 | compileOptions {
69 | sourceCompatibility = BuildVersion.environment.javaVersion
70 | targetCompatibility = BuildVersion.environment.javaVersion
71 | }
72 | }
73 |
74 |
75 | libres {
76 | // https://github.com/Skeptick/libres#setup
77 | }
78 |
79 | task("testClasses").doLast {
80 | println("This is a dummy testClasses task")
81 | }
82 |
83 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
84 |
85 | buildConfig {
86 | // BuildConfig configuration here.
87 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
88 | }
--------------------------------------------------------------------------------
/data/repository/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.com.google.ksp)
8 | }
9 |
10 | kotlin {
11 | androidTarget {
12 | compilations.all {
13 | kotlinOptions {
14 | jvmTarget = BuildVersion.environment.jvmTarget
15 | }
16 | }
17 | }
18 |
19 | jvm()
20 |
21 | listOf(
22 | iosX64(),
23 | iosArm64(),
24 | iosSimulatorArm64()
25 | ).forEach {
26 | it.binaries.framework {
27 | baseName = "data.repository"
28 | isStatic = true
29 | }
30 | }
31 |
32 | sourceSets {
33 | commonMain.dependencies {
34 | implementation(project(mapOf("path" to ":core:common")))
35 | implementation(project(mapOf("path" to ":domain:repository")))
36 | implementation(project(mapOf("path" to ":domain:models")))
37 | implementation(project(mapOf("path" to ":data:models")))
38 | implementation(project(mapOf("path" to ":data:datasources")))
39 | implementation(libs.bundles.layer.core.common)
40 | }
41 |
42 | commonTest.dependencies {
43 | implementation(kotlin("test"))
44 | }
45 |
46 | androidMain.dependencies {
47 | implementation(libs.bundles.android.core)
48 | }
49 |
50 | jvmMain.dependencies {
51 | }
52 |
53 | iosMain.dependencies {
54 | }
55 | }
56 | }
57 |
58 |
59 | android {
60 | namespace = "${BuildVersion.environment.applicationId}.data.repository"
61 | compileSdk = BuildVersion.android.compileSdk
62 | defaultConfig {
63 | minSdk = BuildVersion.android.minSdk
64 | }
65 |
66 | sourceSets["main"].apply {
67 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
68 | res.srcDirs("src/androidMain/resources")
69 | }
70 | compileOptions {
71 | sourceCompatibility = BuildVersion.environment.javaVersion
72 | targetCompatibility = BuildVersion.environment.javaVersion
73 | }
74 | }
75 |
76 | libres {
77 | // https://github.com/Skeptick/libres#setup
78 | }
79 |
80 | task("testClasses").doLast {
81 | println("This is a dummy testClasses task")
82 | }
83 |
84 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
85 |
86 | buildConfig {
87 | // BuildConfig configuration here.
88 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
89 | }
--------------------------------------------------------------------------------
/core/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Shapes.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.foundation.shape.RoundedCornerShape
4 | import androidx.compose.material3.Shapes
5 | import androidx.compose.ui.geometry.Size
6 | import androidx.compose.ui.graphics.Outline
7 | import androidx.compose.ui.graphics.Path
8 | import androidx.compose.ui.graphics.Shape
9 | import androidx.compose.ui.unit.Density
10 | import androidx.compose.ui.unit.LayoutDirection
11 | import androidx.compose.ui.unit.dp
12 |
13 | object TopAppBarShape: Shape {
14 | override fun createOutline(
15 | size: Size,
16 | layoutDirection: LayoutDirection,
17 | density: Density
18 | ): Outline {
19 | val path = Path().apply {
20 | reset()
21 | moveTo(0f, 0f)
22 | lineTo(0f, size.height)
23 | cubicTo(
24 | x1 = size.height * 2,
25 | y1 = size.height * 1.13f,
26 | x2 = size.width * 0.25f,
27 | y2 = size.height * 0.25f,
28 | x3 = (size.width / 2) + (size.width / 3),
29 | y3 = 0f
30 | )
31 | close()
32 | }
33 |
34 | return Outline.Generic(
35 | path = path
36 | )
37 | }
38 | }
39 |
40 | object HeartShape: Shape {
41 | override fun createOutline(
42 | size: Size,
43 | layoutDirection: LayoutDirection,
44 | density: Density
45 | ): Outline {
46 | val path = Path().apply {
47 | heartPath(size = size)
48 | close()
49 | }
50 | return Outline.Generic(path)
51 | }
52 | }
53 |
54 | val AppShapes = Shapes(
55 | extraSmall = RoundedCornerShape(2.dp),
56 | small = RoundedCornerShape(4.dp),
57 | medium = RoundedCornerShape(8.dp),
58 | large = RoundedCornerShape(16.dp),
59 | extraLarge = RoundedCornerShape(32.dp)
60 | )
61 |
62 | private fun Path.heartPath(size: Size): Path {
63 | val width: Float = size.width
64 | val height: Float = size.height
65 |
66 | moveTo(width / 2, height / 5)
67 |
68 | cubicTo(
69 | 5 * width / 14, 0f,
70 | 0f, height / 15,
71 | width / 28, 2 * height / 5
72 | )
73 |
74 | cubicTo(
75 | width / 14, 2 * height / 3,
76 | 3 * width / 7, 5 * height / 6,
77 | width / 2, height
78 | )
79 |
80 | cubicTo(
81 | 4 * width / 7, 5 * height / 6,
82 | 13 * width / 14, 2 * height / 3,
83 | 27 * width / 28, 2 * height / 5
84 | )
85 |
86 | cubicTo(
87 | width, height / 15,
88 | 9 * width / 14, 0f,
89 | width / 2, height / 5
90 | )
91 | return this
92 | }
93 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 |
2 | @rem
3 | @rem Copyright 2015 the original author or authors.
4 | @rem
5 | @rem Licensed under the Apache License, Version 2.0 (the "License");
6 | @rem you may not use this file except in compliance with the License.
7 | @rem You may obtain a copy of the License at
8 | @rem
9 | @rem https://www.apache.org/licenses/LICENSE-2.0
10 | @rem
11 | @rem Unless required by applicable law or agreed to in writing, software
12 | @rem distributed under the License is distributed on an "AS IS" BASIS,
13 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | @rem See the License for the specific language governing permissions and
15 | @rem limitations under the License.
16 | @rem
17 |
18 | @if "%DEBUG%" == "" @echo off
19 | @rem ##########################################################################
20 | @rem
21 | @rem Gradle startup script for Windows
22 | @rem
23 | @rem ##########################################################################
24 |
25 | @rem Set local scope for the variables with windows NT shell
26 | if "%OS%"=="Windows_NT" setlocal
27 |
28 | set DIRNAME=%~dp0
29 | if "%DIRNAME%" == "" set DIRNAME=.
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%" == "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%"=="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 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85 | exit /b 1
86 |
87 | :mainEnd
88 | if "%OS%"=="Windows_NT" endlocal
89 |
90 | :omega
91 |
--------------------------------------------------------------------------------
/data/datasources-core/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.multiplatform)
3 | alias(libs.plugins.android.library)
4 | alias(libs.plugins.libres)
5 | alias(libs.plugins.buildConfig)
6 | alias(libs.plugins.kotlinx.serialization)
7 | alias(libs.plugins.sqlDelight)
8 | alias(libs.plugins.com.google.ksp)
9 | alias(libs.plugins.ktorfit)
10 | }
11 |
12 | kotlin {
13 | androidTarget {
14 | compilations.all {
15 | kotlinOptions {
16 | jvmTarget = BuildVersion.environment.jvmTarget
17 | }
18 | }
19 | }
20 |
21 | jvm()
22 |
23 | listOf(
24 | iosX64(),
25 | iosArm64(),
26 | iosSimulatorArm64()
27 | ).forEach {
28 | it.binaries.framework {
29 | baseName = "dataDatasourcesCore"
30 | isStatic = true
31 | }
32 | }
33 |
34 | dependencies {
35 | add("kspCommonMainMetadata", libs.ktorfit.ksp)
36 | add("kspAndroid", libs.ktorfit.ksp)
37 | add("kspIosArm64", libs.ktorfit.ksp)
38 | add("kspIosX64", libs.ktorfit.ksp)
39 | add("kspIosSimulatorArm64", libs.ktorfit.ksp)
40 | add("kspJvm", libs.ktorfit.ksp)
41 | }
42 |
43 | sourceSets {
44 | commonMain.dependencies {
45 | implementation(project(mapOf("path" to ":core:common")))
46 | implementation(project(mapOf("path" to ":data:models")))
47 | implementation(project(mapOf("path" to ":data:datasources")))
48 |
49 | implementation(libs.bundles.layer.data.datasources.core)
50 | }
51 |
52 | commonTest.dependencies {
53 | implementation(kotlin("test"))
54 | }
55 |
56 | androidMain.dependencies {
57 | implementation(libs.bundles.android.data.core)
58 | }
59 |
60 | jvmMain.dependencies {
61 | implementation(libs.bundles.jvm.data.core)
62 | }
63 |
64 | iosMain.dependencies {
65 | implementation(libs.bundles.ios.data.core)
66 | }
67 |
68 | }
69 | }
70 |
71 |
72 | android {
73 | namespace = "${BuildVersion.environment.applicationId}.data.datasources.core"
74 | compileSdk = BuildVersion.android.compileSdk
75 |
76 | defaultConfig {
77 | minSdk = BuildVersion.android.minSdk
78 | }
79 | sourceSets["main"].apply {
80 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
81 | res.srcDirs("src/androidMain/resources")
82 | }
83 | compileOptions {
84 | sourceCompatibility = BuildVersion.environment.javaVersion
85 | targetCompatibility = BuildVersion.environment.javaVersion
86 | }
87 | }
88 |
89 | libres {
90 | // https://github.com/Skeptick/libres#setup
91 | }
92 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
93 |
94 | buildConfig {
95 | // BuildConfig configuration here.
96 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
97 | }
98 |
99 | sqldelight {
100 | databases {
101 | create(BuildVersion.environment.appDatabaseName) {
102 | // Database configuration here.
103 | // https://cashapp.github.io/sqldelight
104 | packageName.set("${BuildVersion.environment.applicationId}.data.datasources.core.db")
105 | }
106 | }
107 | }
108 |
109 | task("testClasses").doLast {
110 | println("This is a dummy testClasses task")
111 | }
112 |
--------------------------------------------------------------------------------
/.run/androidApp.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/core/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Color.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.ui.graphics.Color
4 |
5 | //generated by https://m3.material.io/theme-builder#/custom
6 | //Color palette was taken here: https://colorhunt.co/palettes/popular
7 |
8 | internal val md_theme_light_primary = Color(0xFF00687A)
9 | internal val md_theme_light_onPrimary = Color(0xFFFFFFFF)
10 | internal val md_theme_light_primaryContainer = Color(0xFFABEDFF)
11 | internal val md_theme_light_onPrimaryContainer = Color(0xFF001F26)
12 | internal val md_theme_light_secondary = Color(0xFF00696E)
13 | internal val md_theme_light_onSecondary = Color(0xFFFFFFFF)
14 | internal val md_theme_light_secondaryContainer = Color(0xFF6FF6FE)
15 | internal val md_theme_light_onSecondaryContainer = Color(0xFF002022)
16 | internal val md_theme_light_tertiary = Color(0xFF904D00)
17 | internal val md_theme_light_onTertiary = Color(0xFFFFFFFF)
18 | internal val md_theme_light_tertiaryContainer = Color(0xFFFFDCC2)
19 | internal val md_theme_light_onTertiaryContainer = Color(0xFF2E1500)
20 | internal val md_theme_light_error = Color(0xFFBA1A1A)
21 | internal val md_theme_light_errorContainer = Color(0xFFFFDAD6)
22 | internal val md_theme_light_onError = Color(0xFFFFFFFF)
23 | internal val md_theme_light_onErrorContainer = Color(0xFF410002)
24 | internal val md_theme_light_background = Color(0xFFFFFBFF)
25 | internal val md_theme_light_onBackground = Color(0xFF221B00)
26 | internal val md_theme_light_surface = Color(0xFFFFFBFF)
27 | internal val md_theme_light_onSurface = Color(0xFF221B00)
28 | internal val md_theme_light_surfaceVariant = Color(0xFFDBE4E7)
29 | internal val md_theme_light_onSurfaceVariant = Color(0xFF3F484B)
30 | internal val md_theme_light_outline = Color(0xFF70797B)
31 | internal val md_theme_light_inverseOnSurface = Color(0xFFFFF0C0)
32 | internal val md_theme_light_inverseSurface = Color(0xFF3A3000)
33 | internal val md_theme_light_inversePrimary = Color(0xFF55D6F4)
34 | internal val md_theme_light_shadow = Color(0xFF000000)
35 | internal val md_theme_light_surfaceTint = Color(0xFF00687A)
36 | internal val md_theme_light_outlineVariant = Color(0xFFBFC8CB)
37 | internal val md_theme_light_scrim = Color(0xFF000000)
38 |
39 | internal val md_theme_dark_primary = Color(0xFF55D6F4)
40 | internal val md_theme_dark_onPrimary = Color(0xFF003640)
41 | internal val md_theme_dark_primaryContainer = Color(0xFF004E5C)
42 | internal val md_theme_dark_onPrimaryContainer = Color(0xFFABEDFF)
43 | internal val md_theme_dark_secondary = Color(0xFF4CD9E2)
44 | internal val md_theme_dark_onSecondary = Color(0xFF00373A)
45 | internal val md_theme_dark_secondaryContainer = Color(0xFF004F53)
46 | internal val md_theme_dark_onSecondaryContainer = Color(0xFF6FF6FE)
47 | internal val md_theme_dark_tertiary = Color(0xFFFFB77C)
48 | internal val md_theme_dark_onTertiary = Color(0xFF4D2700)
49 | internal val md_theme_dark_tertiaryContainer = Color(0xFF6D3900)
50 | internal val md_theme_dark_onTertiaryContainer = Color(0xFFFFDCC2)
51 | internal val md_theme_dark_error = Color(0xFFFFB4AB)
52 | internal val md_theme_dark_errorContainer = Color(0xFF93000A)
53 | internal val md_theme_dark_onError = Color(0xFF690005)
54 | internal val md_theme_dark_onErrorContainer = Color(0xFFFFDAD6)
55 | internal val md_theme_dark_background = Color(0xFF221B00)
56 | internal val md_theme_dark_onBackground = Color(0xFFFFE264)
57 | internal val md_theme_dark_surface = Color(0xFF221B00)
58 | internal val md_theme_dark_onSurface = Color(0xFFFFE264)
59 | internal val md_theme_dark_surfaceVariant = Color(0xFF3F484B)
60 | internal val md_theme_dark_onSurfaceVariant = Color(0xFFBFC8CB)
61 | internal val md_theme_dark_outline = Color(0xFF899295)
62 | internal val md_theme_dark_inverseOnSurface = Color(0xFF221B00)
63 | internal val md_theme_dark_inverseSurface = Color(0xFFFFE264)
64 | internal val md_theme_dark_inversePrimary = Color(0xFF00687A)
65 | internal val md_theme_dark_shadow = Color(0xFF000000)
66 | internal val md_theme_dark_surfaceTint = Color(0xFF55D6F4)
67 | internal val md_theme_dark_outlineVariant = Color(0xFF3F484B)
68 | internal val md_theme_dark_scrim = Color(0xFF000000)
69 |
70 |
71 | internal val seed = Color(0xFF2C3639)
72 |
--------------------------------------------------------------------------------
/presentation/ui/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.compose.desktop.application.dsl.TargetFormat
2 |
3 | plugins {
4 | alias(libs.plugins.multiplatform)
5 | alias(libs.plugins.compose)
6 | alias(libs.plugins.android.application)
7 | alias(libs.plugins.libres)
8 | alias(libs.plugins.buildConfig)
9 | alias(libs.plugins.kotlinx.serialization)
10 | alias(libs.plugins.com.google.ksp)
11 | }
12 |
13 | kotlin {
14 | androidTarget {
15 | compilations.all {
16 | kotlinOptions {
17 | jvmTarget = BuildVersion.environment.jvmTarget
18 | }
19 | }
20 | }
21 |
22 | jvm()
23 |
24 | listOf(
25 | iosX64(),
26 | iosArm64(),
27 | iosSimulatorArm64()
28 | ).forEach {
29 | it.binaries.framework {
30 | baseName = "presentationUi"
31 | isStatic = true
32 | }
33 | }
34 |
35 | sourceSets {
36 | commonMain.dependencies {
37 | implementation(project(mapOf("path" to ":core:ui")))
38 | implementation(project(mapOf("path" to ":core:common")))
39 | implementation(project(mapOf("path" to ":core:di")))
40 | implementation(project(mapOf("path" to ":presentation:viewmodels")))
41 | implementation(project(mapOf("path" to ":domain:models")))
42 | implementation(compose.runtime)
43 | implementation(compose.material3)
44 | implementation(compose.materialIconsExtended)
45 | implementation(libs.bundles.layer.core.ui)
46 | }
47 |
48 | commonTest.dependencies {
49 | implementation(kotlin("test"))
50 | }
51 |
52 | androidMain.dependencies {
53 | implementation(libs.bundles.android.core.ui)
54 | }
55 |
56 | jvmMain.dependencies {
57 | implementation(compose.desktop.common)
58 | implementation(compose.desktop.currentOs)
59 | }
60 |
61 | iosMain.dependencies {
62 |
63 | }
64 | }
65 | }
66 |
67 | android {
68 | namespace = "${BuildVersion.environment.applicationId}.presentation.ui"
69 | compileSdk = BuildVersion.android.compileSdk
70 |
71 | defaultConfig {
72 | minSdk = BuildVersion.android.minSdk
73 | targetSdk = BuildVersion.android.compileSdk
74 |
75 | applicationId = BuildVersion.environment.applicationId
76 | versionCode = BuildVersion.environment.appVersion
77 | versionName = BuildVersion.environment.appVersionCode
78 | }
79 | sourceSets["main"].apply {
80 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
81 | res.srcDirs("src/androidMain/resources")
82 | }
83 | compileOptions {
84 | sourceCompatibility = BuildVersion.environment.javaVersion
85 | targetCompatibility = BuildVersion.environment.javaVersion
86 | }
87 | buildFeatures {
88 | compose = true
89 | }
90 | composeOptions {
91 | kotlinCompilerExtensionVersion = BuildVersion.environment.composeCompilerVersion
92 | }
93 | }
94 |
95 | compose.desktop {
96 | application {
97 | mainClass = "${BuildVersion.environment.applicationId}.MainKt"
98 | fromFiles(project.fileTree("libs/") { include("**/*.jar") })
99 |
100 | nativeDistributions {
101 | targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
102 | packageName = BuildVersion.environment.appName
103 | description = BuildVersion.environment.appDescription
104 | packageVersion = BuildVersion.environment.appVersionCode
105 | includeAllModules = true
106 | javaHome = "/Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk"
107 | vendor = BuildVersion.environment.appVendor
108 | appResourcesRootDir.set(project.layout.projectDirectory.dir("resources"))
109 | windows {
110 | iconFile.set(project.file("src/jvmMain/libres/images/ic_launcher_ico.ico"))
111 | dirChooser = true
112 | //javaHome = "C:\\Program Files\\JetBrains\\IntelliJ IDEA Community Edition 2022.2.2\\jbr"
113 | menuGroup = BuildVersion.environment.menuCategory
114 | }
115 |
116 | macOS{
117 | packageBuildVersion = BuildVersion.environment.appVersionCode
118 | bundleID = "${BuildVersion.environment.applicationId}.MainKt"
119 | dockName = BuildVersion.environment.appName
120 | javaHome = "/Library/Java/JavaVirtualMachines/jdk-17.0.2.jdk"
121 | iconFile.set(project.file("src/iosMain/libres/images/ic_launcher_icns.icns"))
122 | mainClass = "${BuildVersion.environment.applicationId}.MainKt"
123 | appCategory = "public.app-category.developer-tools"
124 | }
125 | }
126 | }
127 | }
128 |
129 |
130 |
131 |
132 | libres {
133 | // https://github.com/Skeptick/libres#setup
134 | generatedClassName = "MainResources"
135 | generateNamedArguments = true
136 | }
137 | tasks.getByPath("jvmProcessResources").dependsOn("libresGenerateResources")
138 | tasks.getByPath("jvmSourcesJar").dependsOn("libresGenerateResources")
139 |
140 | task("testClasses").doLast {
141 | println("This is a dummy testClasses task")
142 | }
143 |
144 | buildConfig {
145 | // BuildConfig configuration here.
146 | // https://github.com/gmazzo/gradle-buildconfig-plugin#usage-in-kts
147 | }
148 |
--------------------------------------------------------------------------------
/presentation/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/presentation/ui/App.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.presentation.ui
2 |
3 | import androidx.compose.foundation.layout.Arrangement
4 | import androidx.compose.foundation.layout.Column
5 | import androidx.compose.foundation.layout.Row
6 | import androidx.compose.foundation.layout.Spacer
7 | import androidx.compose.foundation.layout.WindowInsets
8 | import androidx.compose.foundation.layout.fillMaxSize
9 | import androidx.compose.foundation.layout.fillMaxWidth
10 | import androidx.compose.foundation.layout.padding
11 | import androidx.compose.foundation.layout.safeDrawing
12 | import androidx.compose.foundation.layout.size
13 | import androidx.compose.foundation.layout.windowInsetsPadding
14 | import androidx.compose.foundation.text.KeyboardOptions
15 | import androidx.compose.material.icons.Icons
16 | import androidx.compose.material.icons.filled.Close
17 | import androidx.compose.material.icons.filled.DarkMode
18 | import androidx.compose.material.icons.filled.Edit
19 | import androidx.compose.material.icons.filled.LightMode
20 | import androidx.compose.material3.Button
21 | import androidx.compose.material3.Icon
22 | import androidx.compose.material3.IconButton
23 | import androidx.compose.material3.MaterialTheme
24 | import androidx.compose.material3.OutlinedTextField
25 | import androidx.compose.material3.Text
26 | import androidx.compose.material3.TextButton
27 | import androidx.compose.runtime.Composable
28 | import androidx.compose.runtime.getValue
29 | import androidx.compose.runtime.mutableStateOf
30 | import androidx.compose.runtime.remember
31 | import androidx.compose.runtime.setValue
32 | import androidx.compose.ui.Modifier
33 | import androidx.compose.ui.text.input.KeyboardType
34 | import androidx.compose.ui.text.input.PasswordVisualTransformation
35 | import androidx.compose.ui.text.input.VisualTransformation
36 | import androidx.compose.ui.unit.dp
37 | import io.github.afalabarce.mvvmkmmtemplate.core.common.openUrl
38 | import io.github.afalabarce.mvvmkmmtemplate.core.ui.theme.AppMaterialTheme
39 | import io.github.afalabarce.mvvmkmmtemplate.core.ui.theme.LocalThemeIsDark
40 | import io.github.afalabarce.mvvmkmmtemplate.presentation.ui.di.PresentationUiDependencyInjector
41 | import org.koin.compose.KoinApplication
42 |
43 | @Composable
44 | internal fun App() = KoinApplication(moduleList = {
45 | PresentationUiDependencyInjector.koinModules
46 | }) {
47 | AppMaterialTheme {
48 | var email by remember { mutableStateOf("") }
49 | var password by remember { mutableStateOf("") }
50 | var passwordVisibility by remember { mutableStateOf(false) }
51 |
52 | Column(modifier = Modifier.fillMaxSize().windowInsetsPadding(WindowInsets.safeDrawing)) {
53 |
54 | Row(
55 | horizontalArrangement = Arrangement.Center
56 | ) {
57 | Text(
58 | text = "Login",
59 | style = MaterialTheme.typography.titleMedium,
60 | modifier = Modifier.padding(AppMaterialTheme.dimens.appMargin)
61 | )
62 |
63 | Spacer(modifier = Modifier.weight(1.0f))
64 |
65 | var isDark by LocalThemeIsDark.current
66 | IconButton(
67 | onClick = { isDark = !isDark }
68 | ) {
69 | Icon(
70 | modifier = Modifier.padding(AppMaterialTheme.dimens.minStartSurface).size(20.dp),
71 | imageVector = if (isDark) Icons.Default.LightMode else Icons.Default.DarkMode,
72 | contentDescription = null
73 | )
74 | }
75 | }
76 |
77 | OutlinedTextField(
78 | value = email,
79 | onValueChange = { email = it },
80 | label = { Text("Email") },
81 | singleLine = true,
82 | modifier = Modifier.fillMaxWidth().padding(AppMaterialTheme.dimens.appMargin)
83 | )
84 |
85 | OutlinedTextField(
86 | value = password,
87 | onValueChange = { password = it },
88 | label = { Text("Password") },
89 | singleLine = true,
90 | visualTransformation = if (passwordVisibility) VisualTransformation.None else PasswordVisualTransformation(),
91 | modifier = Modifier.fillMaxWidth().padding(AppMaterialTheme.dimens.appMargin),
92 | keyboardOptions = KeyboardOptions(
93 | keyboardType = KeyboardType.Password
94 | ),
95 | trailingIcon = {
96 | IconButton(onClick = { passwordVisibility = !passwordVisibility }) {
97 | val imageVector = if (passwordVisibility) Icons.Default.Close else Icons.Default.Edit
98 | Icon(imageVector, contentDescription = if (passwordVisibility) "Hide password" else "Show password")
99 | }
100 | }
101 | )
102 |
103 | Button(
104 | onClick = { /* Handle login logic here */ },
105 | modifier = Modifier.fillMaxWidth().padding(AppMaterialTheme.dimens.appMargin)
106 | ) {
107 | Text("Login")
108 | }
109 |
110 | TextButton(
111 | onClick = { openUrl("https://github.com/terrakok") },
112 | modifier = Modifier.fillMaxWidth().padding(AppMaterialTheme.dimens.appMargin)
113 | ) {
114 | Text("Open github")
115 | }
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/core/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Theme.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.foundation.isSystemInDarkTheme
4 | import androidx.compose.material3.ColorScheme
5 | import androidx.compose.material3.lightColorScheme
6 | import androidx.compose.material3.darkColorScheme
7 | import androidx.compose.material3.MaterialTheme
8 | import androidx.compose.material3.Shapes
9 | import androidx.compose.material3.Surface
10 | import androidx.compose.material3.Typography
11 | import androidx.compose.runtime.Composable
12 | import androidx.compose.runtime.CompositionLocalProvider
13 | import androidx.compose.runtime.ReadOnlyComposable
14 | import androidx.compose.runtime.compositionLocalOf
15 | import androidx.compose.runtime.getValue
16 | import androidx.compose.runtime.mutableStateOf
17 | import androidx.compose.runtime.remember
18 |
19 | private val LightColorScheme = lightColorScheme(
20 | primary = md_theme_light_primary,
21 | onPrimary = md_theme_light_onPrimary,
22 | primaryContainer = md_theme_light_primaryContainer,
23 | onPrimaryContainer = md_theme_light_onPrimaryContainer,
24 | secondary = md_theme_light_secondary,
25 | onSecondary = md_theme_light_onSecondary,
26 | secondaryContainer = md_theme_light_secondaryContainer,
27 | onSecondaryContainer = md_theme_light_onSecondaryContainer,
28 | tertiary = md_theme_light_tertiary,
29 | onTertiary = md_theme_light_onTertiary,
30 | tertiaryContainer = md_theme_light_tertiaryContainer,
31 | onTertiaryContainer = md_theme_light_onTertiaryContainer,
32 | error = md_theme_light_error,
33 | errorContainer = md_theme_light_errorContainer,
34 | onError = md_theme_light_onError,
35 | onErrorContainer = md_theme_light_onErrorContainer,
36 | background = md_theme_light_background,
37 | onBackground = md_theme_light_onBackground,
38 | surface = md_theme_light_surface,
39 | onSurface = md_theme_light_onSurface,
40 | surfaceVariant = md_theme_light_surfaceVariant,
41 | onSurfaceVariant = md_theme_light_onSurfaceVariant,
42 | outline = md_theme_light_outline,
43 | inverseOnSurface = md_theme_light_inverseOnSurface,
44 | inverseSurface = md_theme_light_inverseSurface,
45 | inversePrimary = md_theme_light_inversePrimary,
46 | surfaceTint = md_theme_light_surfaceTint,
47 | outlineVariant = md_theme_light_outlineVariant,
48 | scrim = md_theme_light_scrim,
49 | )
50 |
51 | private val DarkColorScheme = darkColorScheme(
52 | primary = md_theme_dark_primary,
53 | onPrimary = md_theme_dark_onPrimary,
54 | primaryContainer = md_theme_dark_primaryContainer,
55 | onPrimaryContainer = md_theme_dark_onPrimaryContainer,
56 | secondary = md_theme_dark_secondary,
57 | onSecondary = md_theme_dark_onSecondary,
58 | secondaryContainer = md_theme_dark_secondaryContainer,
59 | onSecondaryContainer = md_theme_dark_onSecondaryContainer,
60 | tertiary = md_theme_dark_tertiary,
61 | onTertiary = md_theme_dark_onTertiary,
62 | tertiaryContainer = md_theme_dark_tertiaryContainer,
63 | onTertiaryContainer = md_theme_dark_onTertiaryContainer,
64 | error = md_theme_dark_error,
65 | errorContainer = md_theme_dark_errorContainer,
66 | onError = md_theme_dark_onError,
67 | onErrorContainer = md_theme_dark_onErrorContainer,
68 | background = md_theme_dark_background,
69 | onBackground = md_theme_dark_onBackground,
70 | surface = md_theme_dark_surface,
71 | onSurface = md_theme_dark_onSurface,
72 | surfaceVariant = md_theme_dark_surfaceVariant,
73 | onSurfaceVariant = md_theme_dark_onSurfaceVariant,
74 | outline = md_theme_dark_outline,
75 | inverseOnSurface = md_theme_dark_inverseOnSurface,
76 | inverseSurface = md_theme_dark_inverseSurface,
77 | inversePrimary = md_theme_dark_inversePrimary,
78 | surfaceTint = md_theme_dark_surfaceTint,
79 | outlineVariant = md_theme_dark_outlineVariant,
80 | scrim = md_theme_dark_scrim,
81 | )
82 |
83 | val LocalThemeIsDark = compositionLocalOf { mutableStateOf(true) }
84 |
85 | @Composable
86 | fun AppMaterialTheme(
87 | content: @Composable() () -> Unit
88 | ) {
89 | val systemIsDark = isSystemInDarkTheme()
90 | val isDarkState = remember { mutableStateOf(systemIsDark) }
91 | CompositionLocalProvider(
92 | LocalThemeIsDark provides isDarkState
93 | ) {
94 | val isDark by isDarkState
95 | SystemAppearance(!isDark)
96 | MaterialTheme(
97 | colorScheme = if (isDark) DarkColorScheme else LightColorScheme,
98 | typography = Typography,
99 | shapes = AppShapes,
100 | content = {
101 | Surface(content = content)
102 | }
103 | )
104 | }
105 | }
106 |
107 | object AppMaterialTheme {
108 | val colorScheme: ColorScheme
109 | @Composable
110 | @ReadOnlyComposable
111 | get() = MaterialTheme.colorScheme
112 | val typography: Typography
113 | @Composable
114 | @ReadOnlyComposable
115 | get() = MaterialTheme.typography
116 |
117 | /**
118 | * Retrieves the current [Shapes] at the call site's position in the hierarchy.
119 | */
120 | val shapes: Shapes
121 | @Composable
122 | @ReadOnlyComposable
123 | get() = MaterialTheme.shapes
124 |
125 | /**
126 | * Retrieves the current [dimens] at the call site's position in the hierarchy.
127 | */
128 | val dimens: MobileDimens
129 | @Composable
130 | @ReadOnlyComposable
131 | get() = LocalDimension.current
132 |
133 | }
134 |
135 |
136 | @Composable
137 | expect fun SystemAppearance(isDark: Boolean)
138 |
--------------------------------------------------------------------------------
/core/ui/src/commonMain/kotlin/io/github/afalabarce/mvvmkmmtemplate/core/ui/theme/Dimens.kt:
--------------------------------------------------------------------------------
1 | package io.github.afalabarce.mvvmkmmtemplate.core.ui.theme
2 |
3 | import androidx.compose.runtime.staticCompositionLocalOf
4 | import androidx.compose.ui.unit.Dp
5 | import androidx.compose.ui.unit.dp
6 |
7 | internal val LocalDimension = staticCompositionLocalOf { mobileDimensions() }
8 |
9 | @Suppress("LongParameterList")
10 | class MobileDimens(
11 | val none: Dp,
12 | val topSurface: Dp,
13 | val startSurface: Dp,
14 | val endSurface: Dp,
15 | val bottomSurface: Dp,
16 | val minTopSurface: Dp,
17 | val minStartSurface: Dp,
18 | val minEndSurface: Dp,
19 | val minBottomSurface: Dp,
20 | val mediumMarginTopSurface: Dp,
21 | val mediumMarginStartSurface: Dp,
22 | val mediumMarginEndSurface: Dp,
23 | val mediumMarginBottomSurface: Dp,
24 | val largeTopSurface: Dp,
25 | val largeStartSurface: Dp,
26 | val largeEndSurface: Dp,
27 | val largeBottomSurface: Dp,
28 | val appMargin: Dp,
29 | val textFieldCorner: Dp,
30 | val smallIconSize: Dp,
31 | val buttonHeight: Dp,
32 | val dialogCorner: Dp,
33 | val focusedBorder: Dp,
34 | val cornerRadius: Dp,
35 | ){
36 | @Suppress("LongParameterList")
37 | fun copy(
38 | none: Dp = this.none,
39 | topSurface: Dp = this.topSurface,
40 | startSurface: Dp = this.startSurface,
41 | endSurface: Dp = this.endSurface,
42 | bottomSurface: Dp = this.bottomSurface,
43 | appMargin: Dp = this.appMargin,
44 | minTopSurface: Dp = this.minTopSurface,
45 | minStartSurface: Dp = this.minStartSurface,
46 | minEndSurface: Dp = this.minEndSurface,
47 | minBottomSurface: Dp = this.minBottomSurface,
48 | mediumMarginTopSurface: Dp = this.mediumMarginTopSurface,
49 | mediumMarginStartSurface: Dp = this.mediumMarginStartSurface,
50 | mediumMarginEndSurface: Dp = this.mediumMarginEndSurface,
51 | mediumMarginBottomSurface: Dp = this.mediumMarginBottomSurface,
52 | largeTopSurface: Dp = this.largeTopSurface,
53 | largeStartSurface: Dp = this.largeStartSurface,
54 | largeEndSurface: Dp = this.largeEndSurface,
55 | largeBottomSurface: Dp = this.largeBottomSurface,
56 | textFieldCorner: Dp = this.textFieldCorner,
57 | smallIconSize: Dp = this.smallIconSize,
58 | buttonHeight: Dp = this.buttonHeight,
59 | dialogCorner: Dp = this.dialogCorner,
60 | focusedBorder: Dp = this.focusedBorder,
61 | cornerRadius: Dp = this.cornerRadius,
62 | ):MobileDimens = MobileDimens(
63 | none = none,
64 | topSurface = topSurface,
65 | startSurface = startSurface,
66 | endSurface = endSurface,
67 | bottomSurface = bottomSurface,
68 | minTopSurface = minTopSurface,
69 | minStartSurface = minStartSurface,
70 | minEndSurface = minEndSurface,
71 | minBottomSurface = minBottomSurface,
72 | largeTopSurface = largeTopSurface,
73 | largeStartSurface = largeStartSurface,
74 | largeEndSurface = largeEndSurface,
75 | largeBottomSurface = largeBottomSurface,
76 | appMargin = appMargin,
77 | textFieldCorner = textFieldCorner,
78 | smallIconSize = smallIconSize,
79 | buttonHeight = buttonHeight,
80 | mediumMarginTopSurface = mediumMarginTopSurface,
81 | mediumMarginStartSurface = mediumMarginStartSurface,
82 | mediumMarginEndSurface = mediumMarginEndSurface,
83 | mediumMarginBottomSurface = mediumMarginBottomSurface,
84 | dialogCorner = dialogCorner,
85 | focusedBorder = focusedBorder,
86 | cornerRadius = cornerRadius,
87 | )
88 | }
89 |
90 | @Suppress("LongParameterList")
91 | fun mobileDimensions(
92 | none: Dp = 0.dp,
93 | topSurface: Dp = 16.dp,
94 | startSurface: Dp = 16.dp,
95 | endSurface: Dp = 16.dp,
96 | bottomSurface: Dp = 16.dp,
97 | minTopSurface: Dp = 8.dp,
98 | minStartSurface: Dp = 8.dp,
99 | minEndSurface: Dp = 8.dp,
100 | minBottomSurface: Dp = 8.dp,
101 | mediumMarginTopSurface: Dp = 32.dp,
102 | mediumMarginStartSurface: Dp = 32.dp,
103 | mediumMarginEndSurface: Dp = 32.dp,
104 | mediumMarginBottomSurface: Dp = 32.dp,
105 | largeTopSurface: Dp = 48.dp,
106 | largeStartSurface: Dp = 48.dp,
107 | largeEndSurface: Dp = 48.dp,
108 | largeBottomSurface: Dp = 48.dp,
109 | appMargin: Dp = 16.dp,
110 | textFieldCorner: Dp = 12.dp,
111 | smallIconSize: Dp = 32.dp,
112 | buttonHeight: Dp = 48.dp,
113 | dialogCorner: Dp = 14.dp,
114 | focusedBorder: Dp = 4.dp,
115 | cornerRadius: Dp = 6.dp,
116 | ): MobileDimens = MobileDimens(
117 | none = none,
118 | topSurface = topSurface,
119 | startSurface = startSurface,
120 | endSurface = endSurface,
121 | bottomSurface = bottomSurface,
122 | minTopSurface = minTopSurface,
123 | minStartSurface = minStartSurface,
124 | minEndSurface = minEndSurface,
125 | minBottomSurface = minBottomSurface,
126 | mediumMarginTopSurface = mediumMarginTopSurface,
127 | mediumMarginStartSurface = mediumMarginStartSurface,
128 | mediumMarginEndSurface = mediumMarginEndSurface,
129 | mediumMarginBottomSurface = mediumMarginBottomSurface,
130 | largeTopSurface = largeTopSurface,
131 | largeStartSurface = largeStartSurface,
132 | largeEndSurface = largeEndSurface,
133 | largeBottomSurface = largeBottomSurface,
134 | appMargin = appMargin,
135 | textFieldCorner = textFieldCorner,
136 | smallIconSize = smallIconSize,
137 | buttonHeight = buttonHeight,
138 | dialogCorner = dialogCorner,
139 | focusedBorder = focusedBorder,
140 | cornerRadius = cornerRadius,
141 | )
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 |
2 | #!/usr/bin/env sh
3 |
4 | #
5 | # Copyright 2015 the original author or authors.
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # https://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | #
19 |
20 | ##############################################################################
21 | ##
22 | ## Gradle start up script for UN*X
23 | ##
24 | ##############################################################################
25 |
26 | # Attempt to set APP_HOME
27 | # Resolve links: ${'$'}0 may be a link
28 | PRG="$0"
29 | # Need this for relative symlinks.
30 | while [ -h "$PRG" ] ; do
31 | ls=`ls -ld "$PRG"`
32 | link=`expr "$ls" : '.*-> \(.*\)${'$'}'`
33 | if expr "$link" : '/.*' > /dev/null; then
34 | PRG="$link"
35 | else
36 | PRG=`dirname "$PRG"`"/$link"
37 | fi
38 | done
39 | SAVED="`pwd`"
40 | cd "`dirname \"$PRG\"`/" >/dev/null
41 | APP_HOME="`pwd -P`"
42 | cd "$SAVED" >/dev/null
43 |
44 | APP_NAME="Gradle"
45 | APP_BASE_NAME=`basename "$0"`
46 |
47 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
48 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
49 |
50 | # Use the maximum available, or set MAX_FD != -1 to use that value.
51 | MAX_FD="maximum"
52 |
53 | warn () {
54 | echo "${'$'}*"
55 | }
56 |
57 | die () {
58 | echo
59 | echo "${'$'}*"
60 | echo
61 | exit 1
62 | }
63 |
64 | # OS specific support (must be 'true' or 'false').
65 | cygwin=false
66 | msys=false
67 | darwin=false
68 | nonstop=false
69 | case "`uname`" in
70 | CYGWIN* )
71 | cygwin=true
72 | ;;
73 | Darwin* )
74 | darwin=true
75 | ;;
76 | MSYS* | MINGW* )
77 | msys=true
78 | ;;
79 | NONSTOP* )
80 | nonstop=true
81 | ;;
82 | esac
83 |
84 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
85 |
86 |
87 | # Determine the Java command to use to start the JVM.
88 | if [ -n "$JAVA_HOME" ] ; then
89 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
90 | # IBM's JDK on AIX uses strange locations for the executables
91 | JAVACMD="$JAVA_HOME/jre/sh/java"
92 | else
93 | JAVACMD="$JAVA_HOME/bin/java"
94 | fi
95 | if [ ! -x "$JAVACMD" ] ; then
96 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
97 |
98 | Please set the JAVA_HOME variable in your environment to match the
99 | location of your Java installation."
100 | fi
101 | else
102 | JAVACMD="java"
103 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
104 |
105 | Please set the JAVA_HOME variable in your environment to match the
106 | location of your Java installation."
107 | fi
108 |
109 | # Increase the maximum file descriptors if we can.
110 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
111 | MAX_FD_LIMIT=`ulimit -H -n`
112 | if [ $? -eq 0 ] ; then
113 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
114 | MAX_FD="$MAX_FD_LIMIT"
115 | fi
116 | ulimit -n $MAX_FD
117 | if [ $? -ne 0 ] ; then
118 | warn "Could not set maximum file descriptor limit: $MAX_FD"
119 | fi
120 | else
121 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
122 | fi
123 | fi
124 |
125 | # For Darwin, add options to specify how the application appears in the dock
126 | if $darwin; then
127 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
128 | fi
129 |
130 | # For Cygwin or MSYS, switch paths to Windows format before running java
131 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
132 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
133 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
134 |
135 | JAVACMD=`cygpath --unix "$JAVACMD"`
136 |
137 | # We build the pattern for arguments to be converted via cygpath
138 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
139 | SEP=""
140 | for dir in $ROOTDIRSRAW ; do
141 | ROOTDIRS="$ROOTDIRS$SEP$dir"
142 | SEP="|"
143 | done
144 | OURCYGPATTERN="(^($ROOTDIRS))"
145 | # Add a user-defined pattern to the cygpath arguments
146 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
147 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
148 | fi
149 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
150 | i=0
151 | for arg in "$@" ; do
152 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
153 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
154 |
155 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
156 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
157 | else
158 | eval `echo args$i`="\"$arg\""
159 | fi
160 | i=`expr $i + 1`
161 | done
162 | case $i in
163 | 0) set -- ;;
164 | 1) set -- "$args0" ;;
165 | 2) set -- "$args0" "$args1" ;;
166 | 3) set -- "$args0" "$args1" "$args2" ;;
167 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
168 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
169 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
170 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
171 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
172 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
173 | esac
174 | fi
175 |
176 | # Escape application args
177 | save () {
178 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
179 | echo " "
180 | }
181 | APP_ARGS=`save "$@"`
182 |
183 | # Collect all arguments for the java command, following the shell quoting and substitution rules
184 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
185 |
186 | exec "$JAVACMD" "$@"
187 |
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 |
3 | kotlin = "1.9.21"
4 | agp = "8.2.0"
5 | compose = "1.5.11"
6 | androidx-appcompat = "1.6.1"
7 | androidx-activityCompose = "1.8.2"
8 | compose-uitooling = "1.5.4"
9 | libres = "1.2.1"
10 | voyager = "1.0.0-rc10"
11 | composeImageLoader = "1.7.1"
12 | napier = "2.6.1"
13 | buildConfig = "4.1.1"
14 | kotlinx-coroutines = "1.7.3"
15 | moko-mvvm = "0.16.1"
16 | composeIcons = "1.1.0"
17 | kotlinx-serialization = "1.6.1"
18 | kotlinx-datetime = "0.4.1"
19 | multiplatformSettings = "1.1.1"
20 | koin = "3.5.0"
21 | kstore = "0.6.0"
22 | sqlDelight = "2.0.0"
23 | ksp-version = "1.9.21-1.0.16"
24 | ktorVersion = "2.3.6"
25 | ktorfit-version = "1.11.0"
26 | koin-compose-version = "1.1.0"
27 | datastore-version = "1.1.0-alpha07"
28 | constraint-layout-version = "0.3.0-alpha01"
29 |
30 | [libraries]
31 | androidx-activityCompose = { module = "androidx.activity:activity-compose", version.ref = "androidx-activityCompose" }
32 | androidx-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidx-appcompat" }
33 | com-google-ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp-version" }
34 | compose-uitooling = { module = "androidx.compose.ui:ui-tooling", version.ref = "compose-uitooling" }
35 | composeIcons-featherIcons = { module = "br.com.devsrsouza.compose.icons:feather", version.ref = "composeIcons" }
36 | composeImageLoader = { module = "io.github.qdsfdhvh:image-loader", version.ref = "composeImageLoader" }
37 | koin-compose = { module = "io.insert-koin:koin-compose", version.ref = "koin-compose-version" }
38 | koin-core = { module = "io.insert-koin:koin-core", version.ref = "koin" }
39 | koin-core-android = { module = "io.insert-koin:koin-android", version.ref = "koin"}
40 | kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinx-coroutines" }
41 | kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
42 | kotlinx-datetime = { module = "org.jetbrains.kotlinx:kotlinx-datetime", version.ref = "kotlinx-datetime" }
43 | kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
44 | kstore = { module = "io.github.xxfast:kstore", version.ref = "kstore" }
45 | ktor-client-cio-jvm = { module = "io.ktor:ktor-client-cio-jvm", version.ref = "ktorVersion" }
46 | ktor-client-content-negotiation = { module = "io.ktor:ktor-client-content-negotiation", version.ref = "ktorVersion" }
47 | ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktorVersion" }
48 | ktor-client-core-jvm = { module = "io.ktor:ktor-client-core-jvm", version.ref = "ktorVersion" }
49 | ktor-client-curl = { module = "io.ktor:ktor-client-curl", version.ref = "ktorVersion" }
50 | ktor-client-ios = { module = "io.ktor:ktor-client-ios", version.ref = "ktorVersion" }
51 | ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktorVersion" }
52 | ktor-client-mock = { module = "io.ktor:ktor-client-mock", version.ref = "ktorVersion" }
53 | ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktorVersion" }
54 | ktor-client-serialization = { module = "io.ktor:ktor-client-serialization", version.ref = "ktorVersion" }
55 | ktor-serialization-gson = { module = "io.ktor:ktor-serialization-gson", version.ref = "ktorVersion" }
56 | ktor-serialization-kotlinx-json = { module = "io.ktor:ktor-serialization-kotlinx-json", version.ref = "ktorVersion" }
57 | ktorfit-ksp = { module = "de.jensklingenberg.ktorfit:ktorfit-ksp", version.ref = "ktorfit-version" }
58 | ktorfit-lib = { module = "de.jensklingenberg.ktorfit:ktorfit-lib", version.ref = "ktorfit-version" }
59 | libres = { module = "io.github.skeptick.libres:libres-compose", version.ref = "libres" }
60 | moko-mvvm = { module = "dev.icerock.moko:mvvm-compose", version.ref = "moko-mvvm" }
61 | multiplatformSettings = { module = "com.russhwolf:multiplatform-settings", version.ref = "multiplatformSettings" }
62 | napier = { module = "io.github.aakira:napier", version.ref = "napier" }
63 | sqlDelight-driver-android = { module = "app.cash.sqldelight:android-driver", version.ref = "sqlDelight" }
64 | sqlDelight-driver-coroutines-extensions = { module = "app.cash.sqldelight:coroutines-extensions", version.ref = "sqlDelight" }
65 | sqlDelight-driver-native = { module = "app.cash.sqldelight:native-driver", version.ref = "sqlDelight" }
66 | sqlDelight-driver-sqlite = { module = "app.cash.sqldelight:sqlite-driver", version.ref = "sqlDelight" }
67 | voyager-navigator = { module = "cafe.adriel.voyager:voyager-navigator", version.ref = "voyager" }
68 | jetpack-datastore = { module = "androidx.datastore:datastore-preferences-core", version.ref = "datastore-version"}
69 | constraint-layout = { module = "tech.annexflow.compose:constraintlayout-compose-multiplatform", version.ref = "constraint-layout-version"}
70 | [bundles]
71 |
72 | layer-core-common = [
73 | "napier",
74 | "kotlinx-coroutines-core",
75 | "kotlinx-serialization-json",
76 | "kotlinx-datetime",
77 | "multiplatformSettings",
78 | "koin-core"
79 | ]
80 |
81 | layer-core-viewmodels = [
82 | "napier",
83 | "kotlinx-coroutines-core",
84 | "moko-mvvm",
85 | "kotlinx-serialization-json",
86 | "kotlinx-datetime",
87 | "multiplatformSettings",
88 | "koin-core"
89 | ]
90 |
91 | layer-core-ui = [
92 | "libres",
93 | "voyager-navigator",
94 | "composeImageLoader",
95 | "napier",
96 | "kotlinx-coroutines-core",
97 | "composeIcons-featherIcons",
98 | "kotlinx-serialization-json",
99 | "kotlinx-datetime",
100 | "multiplatformSettings",
101 | "koin-core",
102 | "koin-compose",
103 | "constraint-layout"
104 | ]
105 |
106 | layer-data-datasources-core = [
107 | "napier",
108 | "kotlinx-coroutines-core",
109 | "kotlinx-serialization-json",
110 | "kotlinx-datetime",
111 | "multiplatformSettings",
112 | "koin-core",
113 | "kstore",
114 | "ktor-client-core",
115 | "ktor-client-content-negotiation",
116 | "ktor-client-logging",
117 | "ktor-client-serialization",
118 | "ktor-serialization-kotlinx-json",
119 | "ktorfit-lib",
120 | "jetpack-datastore",
121 | "sqlDelight-driver-coroutines-extensions"
122 | ]
123 |
124 | android-core = [
125 | "kotlinx-coroutines-android",
126 | "koin-core-android"
127 | ]
128 |
129 | android-core-ui = [
130 | "androidx-appcompat",
131 | "androidx-activityCompose",
132 | "compose-uitooling",
133 | "kotlinx-coroutines-android",
134 | "koin-core-android"
135 | ]
136 |
137 | android-data-core = [
138 | "kotlinx-coroutines-android",
139 | "ktor-client-okhttp",
140 | "sqlDelight-driver-android",
141 | "koin-core-android"
142 | ]
143 |
144 | jvm-data-core = [
145 | "ktor-client-okhttp",
146 | "ktor-client-core-jvm",
147 | "ktor-client-cio-jvm",
148 | "sqlDelight-driver-sqlite"
149 | ]
150 |
151 | ios-data-core = [
152 | "ktor-client-ios",
153 | "sqlDelight-driver-native"
154 | ]
155 |
156 | [plugins]
157 | multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
158 | compose = { id = "org.jetbrains.compose", version.ref = "compose" }
159 | android-application = { id = "com.android.application", version.ref = "agp" }
160 | android-library = { id = "com.android.library", version.ref = "agp" }
161 | libres = { id = "io.github.skeptick.libres", version.ref = "libres" }
162 | buildConfig = { id = "com.github.gmazzo.buildconfig", version.ref = "buildConfig" }
163 | kotlinx-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
164 | sqlDelight = { id = "app.cash.sqldelight", version.ref = "sqlDelight" }
165 | com-google-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp-version" }
166 | ktorfit = { id ="de.jensklingenberg.ktorfit", version.ref = "ktorfit-version" }
167 |
--------------------------------------------------------------------------------
/iosApp/iosApp.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 56;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | A93A953B29CC810C00F8E227 /* iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A93A953A29CC810C00F8E227 /* iosApp.swift */; };
11 | A93A953F29CC810D00F8E227 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A93A953E29CC810D00F8E227 /* Assets.xcassets */; };
12 | A93A954229CC810D00F8E227 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A93A954129CC810D00F8E227 /* Preview Assets.xcassets */; };
13 | /* End PBXBuildFile section */
14 |
15 | /* Begin PBXFileReference section */
16 | A93A953729CC810C00F8E227 /* MVVM Multiplatform Template.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "MVVM Multiplatform Template.app"; sourceTree = BUILT_PRODUCTS_DIR; };
17 | A93A953A29CC810C00F8E227 /* iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosApp.swift; sourceTree = ""; };
18 | A93A953E29CC810D00F8E227 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
19 | A93A954129CC810D00F8E227 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
20 | /* End PBXFileReference section */
21 |
22 | /* Begin PBXFrameworksBuildPhase section */
23 | A93A953429CC810C00F8E227 /* Frameworks */ = {
24 | isa = PBXFrameworksBuildPhase;
25 | buildActionMask = 2147483647;
26 | files = (
27 | );
28 | runOnlyForDeploymentPostprocessing = 0;
29 | };
30 | /* End PBXFrameworksBuildPhase section */
31 |
32 | /* Begin PBXGroup section */
33 | A93A952E29CC810C00F8E227 = {
34 | isa = PBXGroup;
35 | children = (
36 | A93A953929CC810C00F8E227 /* iosApp */,
37 | A93A953829CC810C00F8E227 /* Products */,
38 | C4127409AE3703430489E7BC /* Frameworks */,
39 | );
40 | sourceTree = "";
41 | };
42 | A93A953829CC810C00F8E227 /* Products */ = {
43 | isa = PBXGroup;
44 | children = (
45 | A93A953729CC810C00F8E227 /* MVVM Multiplatform Template.app */,
46 | );
47 | name = Products;
48 | sourceTree = "";
49 | };
50 | A93A953929CC810C00F8E227 /* iosApp */ = {
51 | isa = PBXGroup;
52 | children = (
53 | A93A953A29CC810C00F8E227 /* iosApp.swift */,
54 | A93A953E29CC810D00F8E227 /* Assets.xcassets */,
55 | A93A954029CC810D00F8E227 /* Preview Content */,
56 | );
57 | path = iosApp;
58 | sourceTree = "";
59 | };
60 | A93A954029CC810D00F8E227 /* Preview Content */ = {
61 | isa = PBXGroup;
62 | children = (
63 | A93A954129CC810D00F8E227 /* Preview Assets.xcassets */,
64 | );
65 | path = "Preview Content";
66 | sourceTree = "";
67 | };
68 | C4127409AE3703430489E7BC /* Frameworks */ = {
69 | isa = PBXGroup;
70 | children = (
71 | );
72 | name = Frameworks;
73 | sourceTree = "";
74 | };
75 | /* End PBXGroup section */
76 |
77 | /* Begin PBXNativeTarget section */
78 | A93A953629CC810C00F8E227 /* iosApp */ = {
79 | isa = PBXNativeTarget;
80 | buildConfigurationList = A93A954529CC810D00F8E227 /* Build configuration list for PBXNativeTarget "iosApp" */;
81 | buildPhases = (
82 | A9D80A052AAB5CDE006C8738 /* ShellScript */,
83 | A93A953329CC810C00F8E227 /* Sources */,
84 | A93A953429CC810C00F8E227 /* Frameworks */,
85 | A93A953529CC810C00F8E227 /* Resources */,
86 | );
87 | buildRules = (
88 | );
89 | dependencies = (
90 | );
91 | name = iosApp;
92 | productName = iosApp;
93 | productReference = A93A953729CC810C00F8E227 /* MVVM Multiplatform Template.app */;
94 | productType = "com.apple.product-type.application";
95 | };
96 | /* End PBXNativeTarget section */
97 |
98 | /* Begin PBXProject section */
99 | A93A952F29CC810C00F8E227 /* Project object */ = {
100 | isa = PBXProject;
101 | attributes = {
102 | LastSwiftUpdateCheck = 1420;
103 | LastUpgradeCheck = 1420;
104 | TargetAttributes = {
105 | A93A953629CC810C00F8E227 = {
106 | CreatedOnToolsVersion = 14.2;
107 | };
108 | };
109 | };
110 | buildConfigurationList = A93A953229CC810C00F8E227 /* Build configuration list for PBXProject "iosApp" */;
111 | compatibilityVersion = "Xcode 14.0";
112 | developmentRegion = en;
113 | hasScannedForEncodings = 0;
114 | knownRegions = (
115 | en,
116 | Base,
117 | );
118 | mainGroup = A93A952E29CC810C00F8E227;
119 | productRefGroup = A93A953829CC810C00F8E227 /* Products */;
120 | projectDirPath = "";
121 | projectRoot = "";
122 | targets = (
123 | A93A953629CC810C00F8E227 /* iosApp */,
124 | );
125 | };
126 | /* End PBXProject section */
127 |
128 | /* Begin PBXResourcesBuildPhase section */
129 | A93A953529CC810C00F8E227 /* Resources */ = {
130 | isa = PBXResourcesBuildPhase;
131 | buildActionMask = 2147483647;
132 | files = (
133 | A93A954229CC810D00F8E227 /* Preview Assets.xcassets in Resources */,
134 | A93A953F29CC810D00F8E227 /* Assets.xcassets in Resources */,
135 | );
136 | runOnlyForDeploymentPostprocessing = 0;
137 | };
138 | /* End PBXResourcesBuildPhase section */
139 |
140 | /* Begin PBXShellScriptBuildPhase section */
141 | A9D80A052AAB5CDE006C8738 /* ShellScript */ = {
142 | isa = PBXShellScriptBuildPhase;
143 | buildActionMask = 2147483647;
144 | files = (
145 | );
146 | inputFileListPaths = (
147 | );
148 | inputPaths = (
149 | );
150 | outputFileListPaths = (
151 | );
152 | outputPaths = (
153 | );
154 | runOnlyForDeploymentPostprocessing = 0;
155 | shellPath = /bin/sh;
156 | shellScript = "cd \"$SRCROOT/..\"\n./gradlew :presentation:ui:embedAndSignAppleFrameworkForXcode\n";
157 | };
158 | /* End PBXShellScriptBuildPhase section */
159 |
160 | /* Begin PBXSourcesBuildPhase section */
161 | A93A953329CC810C00F8E227 /* Sources */ = {
162 | isa = PBXSourcesBuildPhase;
163 | buildActionMask = 2147483647;
164 | files = (
165 | A93A953B29CC810C00F8E227 /* iosApp.swift in Sources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXSourcesBuildPhase section */
170 |
171 | /* Begin XCBuildConfiguration section */
172 | A93A954329CC810D00F8E227 /* Debug */ = {
173 | isa = XCBuildConfiguration;
174 | buildSettings = {
175 | ALWAYS_SEARCH_USER_PATHS = NO;
176 | CADisableMinimumFrameDurationOnPhone = true;
177 | CLANG_ANALYZER_NONNULL = YES;
178 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
179 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
180 | CLANG_ENABLE_MODULES = YES;
181 | CLANG_ENABLE_OBJC_ARC = YES;
182 | CLANG_ENABLE_OBJC_WEAK = YES;
183 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
184 | CLANG_WARN_BOOL_CONVERSION = YES;
185 | CLANG_WARN_COMMA = YES;
186 | CLANG_WARN_CONSTANT_CONVERSION = YES;
187 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
188 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
189 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
190 | CLANG_WARN_EMPTY_BODY = YES;
191 | CLANG_WARN_ENUM_CONVERSION = YES;
192 | CLANG_WARN_INFINITE_RECURSION = YES;
193 | CLANG_WARN_INT_CONVERSION = YES;
194 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
195 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
196 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
197 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
198 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
199 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
200 | CLANG_WARN_STRICT_PROTOTYPES = YES;
201 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
202 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
203 | CLANG_WARN_UNREACHABLE_CODE = YES;
204 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
205 | COPY_PHASE_STRIP = NO;
206 | DEBUG_INFORMATION_FORMAT = dwarf;
207 | ENABLE_STRICT_OBJC_MSGSEND = YES;
208 | ENABLE_TESTABILITY = YES;
209 | GCC_C_LANGUAGE_STANDARD = gnu11;
210 | GCC_DYNAMIC_NO_PIC = NO;
211 | GCC_NO_COMMON_BLOCKS = YES;
212 | GCC_OPTIMIZATION_LEVEL = 0;
213 | GCC_PREPROCESSOR_DEFINITIONS = (
214 | "DEBUG=1",
215 | "$(inherited)",
216 | );
217 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
218 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
219 | GCC_WARN_UNDECLARED_SELECTOR = YES;
220 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
221 | GCC_WARN_UNUSED_FUNCTION = YES;
222 | GCC_WARN_UNUSED_VARIABLE = YES;
223 | IPHONEOS_DEPLOYMENT_TARGET = 16.2;
224 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
225 | MTL_FAST_MATH = YES;
226 | ONLY_ACTIVE_ARCH = YES;
227 | OTHER_LDFLAGS = "-lsqlite3";
228 | SDKROOT = iphoneos;
229 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
230 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
231 | };
232 | name = Debug;
233 | };
234 | A93A954429CC810D00F8E227 /* Release */ = {
235 | isa = XCBuildConfiguration;
236 | buildSettings = {
237 | ALWAYS_SEARCH_USER_PATHS = NO;
238 | CADisableMinimumFrameDurationOnPhone = true;
239 | CLANG_ANALYZER_NONNULL = YES;
240 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
241 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
242 | CLANG_ENABLE_MODULES = YES;
243 | CLANG_ENABLE_OBJC_ARC = YES;
244 | CLANG_ENABLE_OBJC_WEAK = YES;
245 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
246 | CLANG_WARN_BOOL_CONVERSION = YES;
247 | CLANG_WARN_COMMA = YES;
248 | CLANG_WARN_CONSTANT_CONVERSION = YES;
249 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
250 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
251 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
252 | CLANG_WARN_EMPTY_BODY = YES;
253 | CLANG_WARN_ENUM_CONVERSION = YES;
254 | CLANG_WARN_INFINITE_RECURSION = YES;
255 | CLANG_WARN_INT_CONVERSION = YES;
256 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
257 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
258 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
259 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
260 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
261 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
262 | CLANG_WARN_STRICT_PROTOTYPES = YES;
263 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
264 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
265 | CLANG_WARN_UNREACHABLE_CODE = YES;
266 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
267 | COPY_PHASE_STRIP = NO;
268 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
269 | ENABLE_NS_ASSERTIONS = NO;
270 | ENABLE_STRICT_OBJC_MSGSEND = YES;
271 | GCC_C_LANGUAGE_STANDARD = gnu11;
272 | GCC_NO_COMMON_BLOCKS = YES;
273 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
274 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
275 | GCC_WARN_UNDECLARED_SELECTOR = YES;
276 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
277 | GCC_WARN_UNUSED_FUNCTION = YES;
278 | GCC_WARN_UNUSED_VARIABLE = YES;
279 | IPHONEOS_DEPLOYMENT_TARGET = 16.2;
280 | MTL_ENABLE_DEBUG_INFO = NO;
281 | MTL_FAST_MATH = YES;
282 | OTHER_LDFLAGS = "-lsqlite3";
283 | SDKROOT = iphoneos;
284 | SWIFT_COMPILATION_MODE = wholemodule;
285 | SWIFT_OPTIMIZATION_LEVEL = "-O";
286 | VALIDATE_PRODUCT = YES;
287 | };
288 | name = Release;
289 | };
290 | A93A954629CC810D00F8E227 /* Debug */ = {
291 | isa = XCBuildConfiguration;
292 | buildSettings = {
293 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
294 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
295 | CODE_SIGN_STYLE = Automatic;
296 | CURRENT_PROJECT_VERSION = 1;
297 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
298 | ENABLE_PREVIEWS = YES;
299 | FRAMEWORK_SEARCH_PATHS = (
300 | "${inherited}",
301 | "$(SRCROOT)/../presentation/ui/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
302 | );
303 | GENERATE_INFOPLIST_FILE = YES;
304 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
305 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
306 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
307 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
308 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
309 | LD_RUNPATH_SEARCH_PATHS = (
310 | "$(inherited)",
311 | "@executable_path/Frameworks",
312 | );
313 | MARKETING_VERSION = 1.0;
314 | OTHER_LDFLAGS = (
315 | "${inherited}",
316 | "-framework",
317 | presentationUi,
318 | );
319 | PRODUCT_BUNDLE_IDENTIFIER = io.github.afalabarce.mvvmkmmtemplate.iosApp;
320 | PRODUCT_NAME = "MVVM Multiplatform Template";
321 | SWIFT_EMIT_LOC_STRINGS = YES;
322 | SWIFT_VERSION = 5.0;
323 | TARGETED_DEVICE_FAMILY = "1,2";
324 | };
325 | name = Debug;
326 | };
327 | A93A954729CC810D00F8E227 /* Release */ = {
328 | isa = XCBuildConfiguration;
329 | buildSettings = {
330 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
331 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
332 | CODE_SIGN_STYLE = Automatic;
333 | CURRENT_PROJECT_VERSION = 1;
334 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\"";
335 | ENABLE_PREVIEWS = YES;
336 | FRAMEWORK_SEARCH_PATHS = (
337 | "${inherited}",
338 | "$(SRCROOT)/../presentation/ui/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)",
339 | );
340 | GENERATE_INFOPLIST_FILE = YES;
341 | INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
342 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
343 | INFOPLIST_KEY_UILaunchScreen_Generation = YES;
344 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
345 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
346 | LD_RUNPATH_SEARCH_PATHS = (
347 | "$(inherited)",
348 | "@executable_path/Frameworks",
349 | );
350 | MARKETING_VERSION = 1.0;
351 | OTHER_LDFLAGS = (
352 | "${inherited}",
353 | "-framework",
354 | presentationUi,
355 | );
356 | PRODUCT_BUNDLE_IDENTIFIER = io.github.afalabarce.mvvmkmmtemplate.iosApp;
357 | PRODUCT_NAME = "MVVM Multiplatform Template";
358 | SWIFT_EMIT_LOC_STRINGS = YES;
359 | SWIFT_VERSION = 5.0;
360 | TARGETED_DEVICE_FAMILY = "1,2";
361 | };
362 | name = Release;
363 | };
364 | /* End XCBuildConfiguration section */
365 |
366 | /* Begin XCConfigurationList section */
367 | A93A953229CC810C00F8E227 /* Build configuration list for PBXProject "iosApp" */ = {
368 | isa = XCConfigurationList;
369 | buildConfigurations = (
370 | A93A954329CC810D00F8E227 /* Debug */,
371 | A93A954429CC810D00F8E227 /* Release */,
372 | );
373 | defaultConfigurationIsVisible = 0;
374 | defaultConfigurationName = Release;
375 | };
376 | A93A954529CC810D00F8E227 /* Build configuration list for PBXNativeTarget "iosApp" */ = {
377 | isa = XCConfigurationList;
378 | buildConfigurations = (
379 | A93A954629CC810D00F8E227 /* Debug */,
380 | A93A954729CC810D00F8E227 /* Release */,
381 | );
382 | defaultConfigurationIsVisible = 0;
383 | defaultConfigurationName = Release;
384 | };
385 | /* End XCConfigurationList section */
386 | };
387 | rootObject = A93A952F29CC810C00F8E227 /* Project object */;
388 | }
389 |
--------------------------------------------------------------------------------
/art/MVVM KMM Template.graphml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | data
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | domain
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | presentation
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | ui
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | viewmodel
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 | usecase
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 | models
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 | repository
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 | repository
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | models
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 | datasources
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | datasources-core
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 | core
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 | ui
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 | common
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | viewmodels
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 | di
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
341 |
342 |
343 |
344 |
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 |
358 |
359 |
360 |
361 |
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 |
378 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
395 |
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 |
412 |
413 |
414 |
415 |
416 |
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 |
442 |
443 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
467 |
468 |
469 |
470 |
471 |
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 |
485 |
486 |
487 |
488 |
489 |
490 |
491 |
492 |
493 |
494 |
495 |
496 |
497 |
498 |
499 |
500 |
501 |
502 |
503 |
504 |
505 |
506 |
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
515 |
516 |
517 |
518 |
519 |
520 |
521 |
522 |
523 |
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 |
533 |
534 |
535 |
536 |
537 |
538 |
539 |
540 |
541 |
542 |
543 |
544 |
545 |
546 |
547 |
548 |
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 |
557 |
558 |
559 |
560 |
561 |
562 |
563 |
564 |
565 |
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
574 |
575 |
576 |
577 |
578 |
579 |
580 |
581 |
582 |
583 |
584 |
585 |
586 |
587 |
588 |
589 |
590 |
591 |
592 |
593 |
594 |
595 |
596 |
597 |
598 |
599 |
600 |
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 |
613 |
614 |
615 |
616 |
617 |
618 |
619 |
620 |
621 |
622 |
623 |
624 |
625 |
626 |
627 |
628 |
629 |
630 |
631 |
632 |
633 |
634 |
635 |
636 |
637 |
638 |
639 |
640 |
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
670 |
671 |
672 |
673 |
674 |
675 |
676 |
677 |
678 |
679 |
680 |
681 |
682 |
683 |
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
692 |
693 |
694 |
695 |
696 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
710 |
711 |
712 |
713 |
714 |
715 |
716 |
717 |
718 |
719 |
720 |
721 |
722 |
723 |
724 |
725 |
726 |
727 |
728 |
729 |
730 |
731 |
732 |
733 |
734 |
735 |
736 |
737 |
738 |
739 |
740 |
741 |
742 |
743 |
744 |
745 |
746 |
747 |
748 |
749 |
750 |
751 |
752 |
753 |
754 |
755 |
756 |
757 |
758 |
759 |
760 |
761 |
762 |
763 |
764 |
765 |
766 |
767 |
768 |
--------------------------------------------------------------------------------