├── .gitignore ├── LICENSE ├── README.md ├── androidApp ├── build.gradle.kts └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── mindinventory │ │ └── kmm │ │ └── androidApp │ │ ├── EmployeeAdapter.kt │ │ └── MainActivity.kt │ └── res │ ├── layout │ ├── activity_main.xml │ └── row_employee.xml │ └── values │ ├── colors.xml │ ├── string.xml │ └── styles.xml ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── iosApp ├── iosApp.xcodeproj │ └── project.pbxproj ├── iosApp │ ├── AppDelegate.swift │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── Contents.json │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Common Files │ │ └── AppConstants.swift │ ├── ContentView.swift │ ├── Info.plist │ ├── Preview Content │ │ └── Preview Assets.xcassets │ │ │ └── Contents.json │ ├── SceneDelegate.swift │ ├── TableViewCell │ │ ├── EmployeeTblVCell.swift │ │ └── EmployeeTblVCell.xib │ ├── ViewController │ │ ├── ViewController.swift │ │ └── ViewController.xib │ └── main.storyboard ├── iosAppTests │ ├── Info.plist │ └── iosAppTests.swift └── iosAppUITests │ ├── Info.plist │ └── iosAppUITests.swift ├── media ├── kotlin-multiplaform-mobile-iOS.gif └── kotlin-multiplaform-mobile.gif ├── settings.gradle.kts └── shared ├── build.gradle.kts └── src ├── androidMain ├── AndroidManifest.xml └── kotlin │ └── com │ └── mindinventory │ └── kmm │ └── shared │ └── cache │ └── DatabaseDriverFactory.kt ├── commonMain ├── kotlin │ └── com │ │ └── mindinventory │ │ └── kmm │ │ └── shared │ │ ├── EmployeeSDK.kt │ │ ├── cache │ │ ├── Database.kt │ │ └── DatabaseDriverFactory.kt │ │ ├── entity │ │ └── Employee.kt │ │ └── network │ │ └── EmployeeApi.kt └── sqldelight │ └── com │ └── mindinventory │ └── kmm │ └── shared │ └── cache │ ├── AppDatabase.sq │ └── AppDatabaseReadMe.txt └── iosMain └── kotlin └── com └── mindinventory └── kmm └── shared └── cache └── DatabaseDriverFactory.kt /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Mindinventory 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Networking and data storage with Kotlin Multiplatform Mobile(KMM) 2 | 3 | Kotlin Multiplatform Mobile which is also called “KMM” help us to write a single code in pure Kotlin and can use it in both Android and iOS application. 4 | This repositary is the code with corresponding to the network call and offline data-storage. 5 | 6 | 7 | ### Preview 8 | ![image](/media/kotlin-multiplaform-mobile.gif)   ![image](/media/kotlin-multiplaform-mobile-iOS.gif) 9 | 10 | ### Requirements 11 | 12 | * Kotlin plugin > 1.4 13 | * Xcode > 11.3 14 | 15 | # Blog post 16 | 17 | https://medium.com/mindful-engineering/getting-started-with-kotlin-multiplatform-part-1-working-with-mobile-platforms-1fd76ce2f055 18 | 19 | # LICENSE! 20 | 21 | Kotlin Multiplatform Mobile is [MIT-licensed](/LICENSE). 22 | 23 | # Let us know! 24 | We’d be really happy if you send us links to your projects where you use our component. Just send an email to sales@mindinventory.com And do let us know if you have any questions or suggestion regarding our work. 25 | -------------------------------------------------------------------------------- /androidApp/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("com.android.application") 3 | kotlin("android") 4 | id("kotlin-android-extensions") 5 | } 6 | group = "com.mindinventory.kmm" 7 | version = "1.0-SNAPSHOT" 8 | 9 | repositories { 10 | gradlePluginPortal() 11 | google() 12 | jcenter() 13 | mavenCentral() 14 | } 15 | dependencies { 16 | implementation(project(":shared")) 17 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9") 18 | implementation("com.google.android.material:material:1.2.1") 19 | implementation("androidx.appcompat:appcompat:1.2.0") 20 | implementation("androidx.constraintlayout:constraintlayout:2.0.4") 21 | implementation("androidx.core:core-ktx:1.3.2") 22 | implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") 23 | } 24 | android { 25 | compileSdkVersion(29) 26 | defaultConfig { 27 | applicationId = "com.mindinventory.kmm.androidApp" 28 | minSdkVersion(24) 29 | targetSdkVersion(29) 30 | versionCode = 1 31 | versionName = "1.0" 32 | } 33 | buildTypes { 34 | getByName("release") { 35 | isMinifyEnabled = false 36 | } 37 | } 38 | 39 | buildFeatures { 40 | dataBinding = true 41 | } 42 | kotlinOptions { 43 | jvmTarget = JavaVersion.VERSION_1_8.toString() 44 | } 45 | } -------------------------------------------------------------------------------- /androidApp/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /androidApp/src/main/java/com/mindinventory/kmm/androidApp/EmployeeAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.androidApp 2 | 3 | import android.view.LayoutInflater 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import androidx.databinding.DataBindingUtil 7 | import androidx.recyclerview.widget.RecyclerView 8 | import com.mindinventory.kmm.androidApp.databinding.RowEmployeeBinding 9 | import com.mindinventory.kmm.shared.entity.EmployeeDataItem 10 | 11 | class EmployeeAdapter(var launches: List) : 12 | RecyclerView.Adapter() { 13 | 14 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): LaunchViewHolder { 15 | return LayoutInflater.from(parent.context) 16 | .inflate(R.layout.row_employee, parent, false) 17 | .run(::LaunchViewHolder) 18 | } 19 | 20 | override fun getItemCount(): Int = launches.count() 21 | 22 | override fun onBindViewHolder(holder: LaunchViewHolder, position: Int) { 23 | holder.bindData(launches[position]) 24 | } 25 | 26 | inner class LaunchViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 27 | private val mBinding = DataBindingUtil.bind(itemView) 28 | 29 | fun bindData(employee: EmployeeDataItem) { 30 | mBinding?.let { 31 | it.item = employee 32 | it.executePendingBindings() 33 | } 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /androidApp/src/main/java/com/mindinventory/kmm/androidApp/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.androidApp 2 | 3 | import android.os.Bundle 4 | import android.widget.Toast 5 | import androidx.appcompat.app.AppCompatActivity 6 | import androidx.core.view.isVisible 7 | import androidx.databinding.DataBindingUtil 8 | import com.mindinventory.kmm.androidApp.databinding.ActivityMainBinding 9 | import com.mindinventory.kmm.shared.EmployeeSDK 10 | import com.mindinventory.kmm.shared.cache.DatabaseDriverFactory 11 | import kotlinx.coroutines.MainScope 12 | import kotlinx.coroutines.cancel 13 | import kotlinx.coroutines.launch 14 | 15 | class MainActivity : AppCompatActivity() { 16 | 17 | private lateinit var mBinding: ActivityMainBinding 18 | private val mainScope = MainScope() 19 | // Initialising native SqlDriver 20 | private val sdk = EmployeeSDK(DatabaseDriverFactory(this)) 21 | private val adapter = EmployeeAdapter(listOf()) 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_main) 26 | mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main) 27 | mBinding.swlRefresh.setOnRefreshListener { displayLaunches(true) } 28 | mBinding.rvList.adapter = adapter 29 | displayLaunches(false) 30 | } 31 | 32 | override fun onDestroy() { 33 | super.onDestroy() 34 | mainScope.cancel() 35 | } 36 | 37 | private fun displayLaunches(needReload: Boolean) { 38 | if (!needReload) 39 | mBinding.progressBar.isVisible = true 40 | mainScope.launch { 41 | kotlin.runCatching { 42 | // calling shared module code feature which provides employees data 43 | sdk.getEmployees(needReload) 44 | }.onSuccess { 45 | // handle success 46 | adapter.launches = it 47 | adapter.notifyDataSetChanged() 48 | }.onFailure { 49 | // handle exceptions 50 | Toast.makeText(this@MainActivity, it.localizedMessage, Toast.LENGTH_SHORT).show() 51 | } 52 | mBinding.progressBar.isVisible = false 53 | mBinding.swlRefresh.isRefreshing = false 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /androidApp/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 13 | 14 | 22 | 23 | 30 | 31 | 32 | 33 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /androidApp/src/main/res/layout/row_employee.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 21 | 22 | 26 | 27 | 37 | 38 | 48 | 49 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /androidApp/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | #AAE0E0E0 7 | -------------------------------------------------------------------------------- /androidApp/src/main/res/values/string.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | KMM 4 | 5 | Name: %s 6 | Salary: %s 7 | Age: %s 8 | -------------------------------------------------------------------------------- /androidApp/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | buildscript { 2 | val kotlinVersion = "1.4.0" 3 | val sqlDelightVersion: String by project 4 | repositories { 5 | gradlePluginPortal() 6 | jcenter() 7 | google() 8 | mavenCentral() 9 | } 10 | dependencies { 11 | classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion") 12 | classpath("com.android.tools.build:gradle:4.0.2") 13 | classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion") 14 | classpath("com.squareup.sqldelight:gradle-plugin:$sqlDelightVersion") 15 | } 16 | } 17 | group = "com.mindinventory.kmm" 18 | version = "1.0-SNAPSHOT" 19 | 20 | repositories { 21 | mavenCentral() 22 | } 23 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | kotlin.code.style=official 2 | xcodeproj=./iosApp 3 | android.useAndroidX=true 4 | kotlin.mpp.enableGranularSourceSetsMetadata=true 5 | kotlin.native.enableDependencyPropagation=false 6 | sqlDelightVersion=1.4.2 7 | android.databinding.enableV2=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mindinventory/Kotlin-multiplatform-sample/fd4e175b62404b92f825f9ef2ff07540dcffd58a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Nov 02 12:50:11 IST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /iosApp/iosApp.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 68643B29255433870069DE3E /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 68643B28255433860069DE3E /* ViewController.xib */; }; 11 | 68643B2F2554339B0069DE3E /* EmployeeTblVCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 68643B2D2554339B0069DE3E /* EmployeeTblVCell.xib */; }; 12 | 68643B302554339B0069DE3E /* EmployeeTblVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68643B2E2554339B0069DE3E /* EmployeeTblVCell.swift */; }; 13 | 68643B34255433A80069DE3E /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68643B33255433A80069DE3E /* ViewController.swift */; }; 14 | 68643B38255433AE0069DE3E /* main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 68643B37255433AE0069DE3E /* main.storyboard */; }; 15 | 68643B3D2554340C0069DE3E /* AppConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68643B3C2554340C0069DE3E /* AppConstants.swift */; }; 16 | 7555FF7F242A565900829871 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF7E242A565900829871 /* AppDelegate.swift */; }; 17 | 7555FF81242A565900829871 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF80242A565900829871 /* SceneDelegate.swift */; }; 18 | 7555FF83242A565900829871 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF82242A565900829871 /* ContentView.swift */; }; 19 | 7555FF85242A565B00829871 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7555FF84242A565B00829871 /* Assets.xcassets */; }; 20 | 7555FF88242A565B00829871 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 7555FF87242A565B00829871 /* Preview Assets.xcassets */; }; 21 | 7555FF8B242A565B00829871 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7555FF89242A565B00829871 /* LaunchScreen.storyboard */; }; 22 | 7555FF96242A565B00829871 /* iosAppTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FF95242A565B00829871 /* iosAppTests.swift */; }; 23 | 7555FFA1242A565B00829871 /* iosAppUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7555FFA0242A565B00829871 /* iosAppUITests.swift */; }; 24 | 7555FFB2242A642300829871 /* shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7555FFB1242A642300829871 /* shared.framework */; }; 25 | 7555FFB3242A642300829871 /* shared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7555FFB1242A642300829871 /* shared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXContainerItemProxy section */ 29 | 7555FF92242A565B00829871 /* PBXContainerItemProxy */ = { 30 | isa = PBXContainerItemProxy; 31 | containerPortal = 7555FF73242A565900829871 /* Project object */; 32 | proxyType = 1; 33 | remoteGlobalIDString = 7555FF7A242A565900829871; 34 | remoteInfo = iosApp; 35 | }; 36 | 7555FF9D242A565B00829871 /* PBXContainerItemProxy */ = { 37 | isa = PBXContainerItemProxy; 38 | containerPortal = 7555FF73242A565900829871 /* Project object */; 39 | proxyType = 1; 40 | remoteGlobalIDString = 7555FF7A242A565900829871; 41 | remoteInfo = iosApp; 42 | }; 43 | /* End PBXContainerItemProxy section */ 44 | 45 | /* Begin PBXCopyFilesBuildPhase section */ 46 | 7555FFB4242A642300829871 /* Embed Frameworks */ = { 47 | isa = PBXCopyFilesBuildPhase; 48 | buildActionMask = 2147483647; 49 | dstPath = ""; 50 | dstSubfolderSpec = 10; 51 | files = ( 52 | 7555FFB3242A642300829871 /* shared.framework in Embed Frameworks */, 53 | ); 54 | name = "Embed Frameworks"; 55 | runOnlyForDeploymentPostprocessing = 0; 56 | }; 57 | /* End PBXCopyFilesBuildPhase section */ 58 | 59 | /* Begin PBXFileReference section */ 60 | 68643B28255433860069DE3E /* ViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = ""; }; 61 | 68643B2D2554339B0069DE3E /* EmployeeTblVCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = EmployeeTblVCell.xib; sourceTree = ""; }; 62 | 68643B2E2554339B0069DE3E /* EmployeeTblVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmployeeTblVCell.swift; sourceTree = ""; }; 63 | 68643B33255433A80069DE3E /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 64 | 68643B37255433AE0069DE3E /* main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = main.storyboard; sourceTree = ""; }; 65 | 68643B3C2554340C0069DE3E /* AppConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppConstants.swift; sourceTree = ""; }; 66 | 7555FF7B242A565900829871 /* iosApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = iosApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 67 | 7555FF7E242A565900829871 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 68 | 7555FF80242A565900829871 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 69 | 7555FF82242A565900829871 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 70 | 7555FF84242A565B00829871 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 71 | 7555FF87242A565B00829871 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; 72 | 7555FF8A242A565B00829871 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 73 | 7555FF8C242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 74 | 7555FF91242A565B00829871 /* iosAppTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iosAppTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 75 | 7555FF95242A565B00829871 /* iosAppTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosAppTests.swift; sourceTree = ""; }; 76 | 7555FF97242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 77 | 7555FF9C242A565B00829871 /* iosAppUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = iosAppUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 78 | 7555FFA0242A565B00829871 /* iosAppUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = iosAppUITests.swift; sourceTree = ""; }; 79 | 7555FFA2242A565B00829871 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 80 | 7555FFB1242A642300829871 /* shared.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = shared.framework; path = "../shared/build/xcode-frameworks/shared.framework"; sourceTree = ""; }; 81 | /* End PBXFileReference section */ 82 | 83 | /* Begin PBXFrameworksBuildPhase section */ 84 | 7555FF78242A565900829871 /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | 7555FFB2242A642300829871 /* shared.framework in Frameworks */, 89 | ); 90 | runOnlyForDeploymentPostprocessing = 0; 91 | }; 92 | 7555FF8E242A565B00829871 /* Frameworks */ = { 93 | isa = PBXFrameworksBuildPhase; 94 | buildActionMask = 2147483647; 95 | files = ( 96 | ); 97 | runOnlyForDeploymentPostprocessing = 0; 98 | }; 99 | 7555FF99242A565B00829871 /* Frameworks */ = { 100 | isa = PBXFrameworksBuildPhase; 101 | buildActionMask = 2147483647; 102 | files = ( 103 | ); 104 | runOnlyForDeploymentPostprocessing = 0; 105 | }; 106 | /* End PBXFrameworksBuildPhase section */ 107 | 108 | /* Begin PBXGroup section */ 109 | 68643B272554337C0069DE3E /* ViewController */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 68643B33255433A80069DE3E /* ViewController.swift */, 113 | 68643B28255433860069DE3E /* ViewController.xib */, 114 | ); 115 | path = ViewController; 116 | sourceTree = ""; 117 | }; 118 | 68643B2C2554338B0069DE3E /* TableViewCell */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 68643B2E2554339B0069DE3E /* EmployeeTblVCell.swift */, 122 | 68643B2D2554339B0069DE3E /* EmployeeTblVCell.xib */, 123 | ); 124 | path = TableViewCell; 125 | sourceTree = ""; 126 | }; 127 | 68643B3B255433F60069DE3E /* Common Files */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 68643B3C2554340C0069DE3E /* AppConstants.swift */, 131 | ); 132 | path = "Common Files"; 133 | sourceTree = ""; 134 | }; 135 | 7555FF72242A565900829871 = { 136 | isa = PBXGroup; 137 | children = ( 138 | 7555FF7D242A565900829871 /* iosApp */, 139 | 7555FF94242A565B00829871 /* iosAppTests */, 140 | 7555FF9F242A565B00829871 /* iosAppUITests */, 141 | 7555FF7C242A565900829871 /* Products */, 142 | 7555FFB0242A642200829871 /* Frameworks */, 143 | ); 144 | sourceTree = ""; 145 | }; 146 | 7555FF7C242A565900829871 /* Products */ = { 147 | isa = PBXGroup; 148 | children = ( 149 | 7555FF7B242A565900829871 /* iosApp.app */, 150 | 7555FF91242A565B00829871 /* iosAppTests.xctest */, 151 | 7555FF9C242A565B00829871 /* iosAppUITests.xctest */, 152 | ); 153 | name = Products; 154 | sourceTree = ""; 155 | }; 156 | 7555FF7D242A565900829871 /* iosApp */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 7555FF7E242A565900829871 /* AppDelegate.swift */, 160 | 7555FF80242A565900829871 /* SceneDelegate.swift */, 161 | 7555FF82242A565900829871 /* ContentView.swift */, 162 | 68643B37255433AE0069DE3E /* main.storyboard */, 163 | 68643B3B255433F60069DE3E /* Common Files */, 164 | 68643B272554337C0069DE3E /* ViewController */, 165 | 68643B2C2554338B0069DE3E /* TableViewCell */, 166 | 7555FF84242A565B00829871 /* Assets.xcassets */, 167 | 7555FF89242A565B00829871 /* LaunchScreen.storyboard */, 168 | 7555FF8C242A565B00829871 /* Info.plist */, 169 | 7555FF86242A565B00829871 /* Preview Content */, 170 | ); 171 | path = iosApp; 172 | sourceTree = ""; 173 | }; 174 | 7555FF86242A565B00829871 /* Preview Content */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 7555FF87242A565B00829871 /* Preview Assets.xcassets */, 178 | ); 179 | path = "Preview Content"; 180 | sourceTree = ""; 181 | }; 182 | 7555FF94242A565B00829871 /* iosAppTests */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 7555FF95242A565B00829871 /* iosAppTests.swift */, 186 | 7555FF97242A565B00829871 /* Info.plist */, 187 | ); 188 | path = iosAppTests; 189 | sourceTree = ""; 190 | }; 191 | 7555FF9F242A565B00829871 /* iosAppUITests */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 7555FFA0242A565B00829871 /* iosAppUITests.swift */, 195 | 7555FFA2242A565B00829871 /* Info.plist */, 196 | ); 197 | path = iosAppUITests; 198 | sourceTree = ""; 199 | }; 200 | 7555FFB0242A642200829871 /* Frameworks */ = { 201 | isa = PBXGroup; 202 | children = ( 203 | 7555FFB1242A642300829871 /* shared.framework */, 204 | ); 205 | name = Frameworks; 206 | sourceTree = ""; 207 | }; 208 | /* End PBXGroup section */ 209 | 210 | /* Begin PBXNativeTarget section */ 211 | 7555FF7A242A565900829871 /* iosApp */ = { 212 | isa = PBXNativeTarget; 213 | buildConfigurationList = 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */; 214 | buildPhases = ( 215 | 7555FFB5242A651A00829871 /* ShellScript */, 216 | 7555FF77242A565900829871 /* Sources */, 217 | 7555FF78242A565900829871 /* Frameworks */, 218 | 7555FF79242A565900829871 /* Resources */, 219 | 7555FFB4242A642300829871 /* Embed Frameworks */, 220 | ); 221 | buildRules = ( 222 | ); 223 | dependencies = ( 224 | ); 225 | name = iosApp; 226 | productName = iosApp; 227 | productReference = 7555FF7B242A565900829871 /* iosApp.app */; 228 | productType = "com.apple.product-type.application"; 229 | }; 230 | 7555FF90242A565B00829871 /* iosAppTests */ = { 231 | isa = PBXNativeTarget; 232 | buildConfigurationList = 7555FFA8242A565B00829871 /* Build configuration list for PBXNativeTarget "iosAppTests" */; 233 | buildPhases = ( 234 | 7555FF8D242A565B00829871 /* Sources */, 235 | 7555FF8E242A565B00829871 /* Frameworks */, 236 | 7555FF8F242A565B00829871 /* Resources */, 237 | ); 238 | buildRules = ( 239 | ); 240 | dependencies = ( 241 | 7555FF93242A565B00829871 /* PBXTargetDependency */, 242 | ); 243 | name = iosAppTests; 244 | productName = iosAppTests; 245 | productReference = 7555FF91242A565B00829871 /* iosAppTests.xctest */; 246 | productType = "com.apple.product-type.bundle.unit-test"; 247 | }; 248 | 7555FF9B242A565B00829871 /* iosAppUITests */ = { 249 | isa = PBXNativeTarget; 250 | buildConfigurationList = 7555FFAB242A565B00829871 /* Build configuration list for PBXNativeTarget "iosAppUITests" */; 251 | buildPhases = ( 252 | 7555FF98242A565B00829871 /* Sources */, 253 | 7555FF99242A565B00829871 /* Frameworks */, 254 | 7555FF9A242A565B00829871 /* Resources */, 255 | ); 256 | buildRules = ( 257 | ); 258 | dependencies = ( 259 | 7555FF9E242A565B00829871 /* PBXTargetDependency */, 260 | ); 261 | name = iosAppUITests; 262 | productName = iosAppUITests; 263 | productReference = 7555FF9C242A565B00829871 /* iosAppUITests.xctest */; 264 | productType = "com.apple.product-type.bundle.ui-testing"; 265 | }; 266 | /* End PBXNativeTarget section */ 267 | 268 | /* Begin PBXProject section */ 269 | 7555FF73242A565900829871 /* Project object */ = { 270 | isa = PBXProject; 271 | attributes = { 272 | LastSwiftUpdateCheck = 1130; 273 | LastUpgradeCheck = 1130; 274 | ORGANIZATIONNAME = orgName; 275 | TargetAttributes = { 276 | 7555FF7A242A565900829871 = { 277 | CreatedOnToolsVersion = 11.3.1; 278 | }; 279 | 7555FF90242A565B00829871 = { 280 | CreatedOnToolsVersion = 11.3.1; 281 | TestTargetID = 7555FF7A242A565900829871; 282 | }; 283 | 7555FF9B242A565B00829871 = { 284 | CreatedOnToolsVersion = 11.3.1; 285 | TestTargetID = 7555FF7A242A565900829871; 286 | }; 287 | }; 288 | }; 289 | buildConfigurationList = 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */; 290 | compatibilityVersion = "Xcode 9.3"; 291 | developmentRegion = en; 292 | hasScannedForEncodings = 0; 293 | knownRegions = ( 294 | en, 295 | Base, 296 | ); 297 | mainGroup = 7555FF72242A565900829871; 298 | productRefGroup = 7555FF7C242A565900829871 /* Products */; 299 | projectDirPath = ""; 300 | projectRoot = ""; 301 | targets = ( 302 | 7555FF7A242A565900829871 /* iosApp */, 303 | 7555FF90242A565B00829871 /* iosAppTests */, 304 | 7555FF9B242A565B00829871 /* iosAppUITests */, 305 | ); 306 | }; 307 | /* End PBXProject section */ 308 | 309 | /* Begin PBXResourcesBuildPhase section */ 310 | 7555FF79242A565900829871 /* Resources */ = { 311 | isa = PBXResourcesBuildPhase; 312 | buildActionMask = 2147483647; 313 | files = ( 314 | 7555FF8B242A565B00829871 /* LaunchScreen.storyboard in Resources */, 315 | 68643B38255433AE0069DE3E /* main.storyboard in Resources */, 316 | 7555FF88242A565B00829871 /* Preview Assets.xcassets in Resources */, 317 | 68643B2F2554339B0069DE3E /* EmployeeTblVCell.xib in Resources */, 318 | 68643B29255433870069DE3E /* ViewController.xib in Resources */, 319 | 7555FF85242A565B00829871 /* Assets.xcassets in Resources */, 320 | ); 321 | runOnlyForDeploymentPostprocessing = 0; 322 | }; 323 | 7555FF8F242A565B00829871 /* Resources */ = { 324 | isa = PBXResourcesBuildPhase; 325 | buildActionMask = 2147483647; 326 | files = ( 327 | ); 328 | runOnlyForDeploymentPostprocessing = 0; 329 | }; 330 | 7555FF9A242A565B00829871 /* Resources */ = { 331 | isa = PBXResourcesBuildPhase; 332 | buildActionMask = 2147483647; 333 | files = ( 334 | ); 335 | runOnlyForDeploymentPostprocessing = 0; 336 | }; 337 | /* End PBXResourcesBuildPhase section */ 338 | 339 | /* Begin PBXShellScriptBuildPhase section */ 340 | 7555FFB5242A651A00829871 /* ShellScript */ = { 341 | isa = PBXShellScriptBuildPhase; 342 | buildActionMask = 2147483647; 343 | files = ( 344 | ); 345 | inputFileListPaths = ( 346 | ); 347 | inputPaths = ( 348 | ); 349 | outputFileListPaths = ( 350 | ); 351 | outputPaths = ( 352 | ); 353 | runOnlyForDeploymentPostprocessing = 0; 354 | shellPath = /bin/sh; 355 | shellScript = "cd \"$SRCROOT/..\"\n./gradlew :shared:packForXCode -PXCODE_CONFIGURATION=${CONFIGURATION}\n"; 356 | }; 357 | /* End PBXShellScriptBuildPhase section */ 358 | 359 | /* Begin PBXSourcesBuildPhase section */ 360 | 7555FF77242A565900829871 /* Sources */ = { 361 | isa = PBXSourcesBuildPhase; 362 | buildActionMask = 2147483647; 363 | files = ( 364 | 68643B34255433A80069DE3E /* ViewController.swift in Sources */, 365 | 68643B3D2554340C0069DE3E /* AppConstants.swift in Sources */, 366 | 7555FF7F242A565900829871 /* AppDelegate.swift in Sources */, 367 | 68643B302554339B0069DE3E /* EmployeeTblVCell.swift in Sources */, 368 | 7555FF81242A565900829871 /* SceneDelegate.swift in Sources */, 369 | 7555FF83242A565900829871 /* ContentView.swift in Sources */, 370 | ); 371 | runOnlyForDeploymentPostprocessing = 0; 372 | }; 373 | 7555FF8D242A565B00829871 /* Sources */ = { 374 | isa = PBXSourcesBuildPhase; 375 | buildActionMask = 2147483647; 376 | files = ( 377 | 7555FF96242A565B00829871 /* iosAppTests.swift in Sources */, 378 | ); 379 | runOnlyForDeploymentPostprocessing = 0; 380 | }; 381 | 7555FF98242A565B00829871 /* Sources */ = { 382 | isa = PBXSourcesBuildPhase; 383 | buildActionMask = 2147483647; 384 | files = ( 385 | 7555FFA1242A565B00829871 /* iosAppUITests.swift in Sources */, 386 | ); 387 | runOnlyForDeploymentPostprocessing = 0; 388 | }; 389 | /* End PBXSourcesBuildPhase section */ 390 | 391 | /* Begin PBXTargetDependency section */ 392 | 7555FF93242A565B00829871 /* PBXTargetDependency */ = { 393 | isa = PBXTargetDependency; 394 | target = 7555FF7A242A565900829871 /* iosApp */; 395 | targetProxy = 7555FF92242A565B00829871 /* PBXContainerItemProxy */; 396 | }; 397 | 7555FF9E242A565B00829871 /* PBXTargetDependency */ = { 398 | isa = PBXTargetDependency; 399 | target = 7555FF7A242A565900829871 /* iosApp */; 400 | targetProxy = 7555FF9D242A565B00829871 /* PBXContainerItemProxy */; 401 | }; 402 | /* End PBXTargetDependency section */ 403 | 404 | /* Begin PBXVariantGroup section */ 405 | 7555FF89242A565B00829871 /* LaunchScreen.storyboard */ = { 406 | isa = PBXVariantGroup; 407 | children = ( 408 | 7555FF8A242A565B00829871 /* Base */, 409 | ); 410 | name = LaunchScreen.storyboard; 411 | sourceTree = ""; 412 | }; 413 | /* End PBXVariantGroup section */ 414 | 415 | /* Begin XCBuildConfiguration section */ 416 | 7555FFA3242A565B00829871 /* Debug */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | ALWAYS_SEARCH_USER_PATHS = NO; 420 | CLANG_ANALYZER_NONNULL = YES; 421 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 422 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 423 | CLANG_CXX_LIBRARY = "libc++"; 424 | CLANG_ENABLE_MODULES = YES; 425 | CLANG_ENABLE_OBJC_ARC = YES; 426 | CLANG_ENABLE_OBJC_WEAK = YES; 427 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 428 | CLANG_WARN_BOOL_CONVERSION = YES; 429 | CLANG_WARN_COMMA = YES; 430 | CLANG_WARN_CONSTANT_CONVERSION = YES; 431 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 432 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 433 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 434 | CLANG_WARN_EMPTY_BODY = YES; 435 | CLANG_WARN_ENUM_CONVERSION = YES; 436 | CLANG_WARN_INFINITE_RECURSION = YES; 437 | CLANG_WARN_INT_CONVERSION = YES; 438 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 439 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 440 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 441 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 442 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 443 | CLANG_WARN_STRICT_PROTOTYPES = YES; 444 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 445 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 446 | CLANG_WARN_UNREACHABLE_CODE = YES; 447 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 448 | COPY_PHASE_STRIP = NO; 449 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 450 | ENABLE_STRICT_OBJC_MSGSEND = YES; 451 | ENABLE_TESTABILITY = YES; 452 | GCC_C_LANGUAGE_STANDARD = gnu11; 453 | GCC_DYNAMIC_NO_PIC = NO; 454 | GCC_NO_COMMON_BLOCKS = YES; 455 | GCC_OPTIMIZATION_LEVEL = 0; 456 | GCC_PREPROCESSOR_DEFINITIONS = ( 457 | "DEBUG=1", 458 | "$(inherited)", 459 | ); 460 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 461 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 462 | GCC_WARN_UNDECLARED_SELECTOR = YES; 463 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 464 | GCC_WARN_UNUSED_FUNCTION = YES; 465 | GCC_WARN_UNUSED_VARIABLE = YES; 466 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 467 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; 468 | MTL_FAST_MATH = YES; 469 | ONLY_ACTIVE_ARCH = YES; 470 | SDKROOT = iphoneos; 471 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 472 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 473 | }; 474 | name = Debug; 475 | }; 476 | 7555FFA4242A565B00829871 /* Release */ = { 477 | isa = XCBuildConfiguration; 478 | buildSettings = { 479 | ALWAYS_SEARCH_USER_PATHS = NO; 480 | CLANG_ANALYZER_NONNULL = YES; 481 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 482 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 483 | CLANG_CXX_LIBRARY = "libc++"; 484 | CLANG_ENABLE_MODULES = YES; 485 | CLANG_ENABLE_OBJC_ARC = YES; 486 | CLANG_ENABLE_OBJC_WEAK = YES; 487 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 488 | CLANG_WARN_BOOL_CONVERSION = YES; 489 | CLANG_WARN_COMMA = YES; 490 | CLANG_WARN_CONSTANT_CONVERSION = YES; 491 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 492 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 493 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 494 | CLANG_WARN_EMPTY_BODY = YES; 495 | CLANG_WARN_ENUM_CONVERSION = YES; 496 | CLANG_WARN_INFINITE_RECURSION = YES; 497 | CLANG_WARN_INT_CONVERSION = YES; 498 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 499 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 500 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 501 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 502 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 503 | CLANG_WARN_STRICT_PROTOTYPES = YES; 504 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 505 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 506 | CLANG_WARN_UNREACHABLE_CODE = YES; 507 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 508 | COPY_PHASE_STRIP = NO; 509 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 510 | ENABLE_NS_ASSERTIONS = NO; 511 | ENABLE_STRICT_OBJC_MSGSEND = YES; 512 | GCC_C_LANGUAGE_STANDARD = gnu11; 513 | GCC_NO_COMMON_BLOCKS = YES; 514 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 515 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 516 | GCC_WARN_UNDECLARED_SELECTOR = YES; 517 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 518 | GCC_WARN_UNUSED_FUNCTION = YES; 519 | GCC_WARN_UNUSED_VARIABLE = YES; 520 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 521 | MTL_ENABLE_DEBUG_INFO = NO; 522 | MTL_FAST_MATH = YES; 523 | SDKROOT = iphoneos; 524 | SWIFT_COMPILATION_MODE = wholemodule; 525 | SWIFT_OPTIMIZATION_LEVEL = "-O"; 526 | VALIDATE_PRODUCT = YES; 527 | }; 528 | name = Release; 529 | }; 530 | 7555FFA6242A565B00829871 /* Debug */ = { 531 | isa = XCBuildConfiguration; 532 | buildSettings = { 533 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 534 | CODE_SIGN_STYLE = Automatic; 535 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 536 | ENABLE_PREVIEWS = YES; 537 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks"; 538 | INFOPLIST_FILE = iosApp/Info.plist; 539 | LD_RUNPATH_SEARCH_PATHS = ( 540 | "$(inherited)", 541 | "@executable_path/Frameworks", 542 | ); 543 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp; 544 | PRODUCT_NAME = "$(TARGET_NAME)"; 545 | SWIFT_VERSION = 5.0; 546 | TARGETED_DEVICE_FAMILY = "1,2"; 547 | }; 548 | name = Debug; 549 | }; 550 | 7555FFA7242A565B00829871 /* Release */ = { 551 | isa = XCBuildConfiguration; 552 | buildSettings = { 553 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 554 | CODE_SIGN_STYLE = Automatic; 555 | DEVELOPMENT_ASSET_PATHS = "\"iosApp/Preview Content\""; 556 | ENABLE_PREVIEWS = YES; 557 | FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/../shared/build/xcode-frameworks"; 558 | INFOPLIST_FILE = iosApp/Info.plist; 559 | LD_RUNPATH_SEARCH_PATHS = ( 560 | "$(inherited)", 561 | "@executable_path/Frameworks", 562 | ); 563 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosApp; 564 | PRODUCT_NAME = "$(TARGET_NAME)"; 565 | SWIFT_VERSION = 5.0; 566 | TARGETED_DEVICE_FAMILY = "1,2"; 567 | }; 568 | name = Release; 569 | }; 570 | 7555FFA9242A565B00829871 /* Debug */ = { 571 | isa = XCBuildConfiguration; 572 | buildSettings = { 573 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 574 | BUNDLE_LOADER = "$(TEST_HOST)"; 575 | CODE_SIGN_STYLE = Automatic; 576 | INFOPLIST_FILE = iosAppTests/Info.plist; 577 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 578 | LD_RUNPATH_SEARCH_PATHS = ( 579 | "$(inherited)", 580 | "@executable_path/Frameworks", 581 | "@loader_path/Frameworks", 582 | ); 583 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosAppTests; 584 | PRODUCT_NAME = "$(TARGET_NAME)"; 585 | SWIFT_VERSION = 5.0; 586 | TARGETED_DEVICE_FAMILY = "1,2"; 587 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iosApp.app/iosApp"; 588 | }; 589 | name = Debug; 590 | }; 591 | 7555FFAA242A565B00829871 /* Release */ = { 592 | isa = XCBuildConfiguration; 593 | buildSettings = { 594 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 595 | BUNDLE_LOADER = "$(TEST_HOST)"; 596 | CODE_SIGN_STYLE = Automatic; 597 | INFOPLIST_FILE = iosAppTests/Info.plist; 598 | IPHONEOS_DEPLOYMENT_TARGET = 13.2; 599 | LD_RUNPATH_SEARCH_PATHS = ( 600 | "$(inherited)", 601 | "@executable_path/Frameworks", 602 | "@loader_path/Frameworks", 603 | ); 604 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosAppTests; 605 | PRODUCT_NAME = "$(TARGET_NAME)"; 606 | SWIFT_VERSION = 5.0; 607 | TARGETED_DEVICE_FAMILY = "1,2"; 608 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/iosApp.app/iosApp"; 609 | }; 610 | name = Release; 611 | }; 612 | 7555FFAC242A565B00829871 /* Debug */ = { 613 | isa = XCBuildConfiguration; 614 | buildSettings = { 615 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 616 | CODE_SIGN_STYLE = Automatic; 617 | INFOPLIST_FILE = iosAppUITests/Info.plist; 618 | LD_RUNPATH_SEARCH_PATHS = ( 619 | "$(inherited)", 620 | "@executable_path/Frameworks", 621 | "@loader_path/Frameworks", 622 | ); 623 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosAppUITests; 624 | PRODUCT_NAME = "$(TARGET_NAME)"; 625 | SWIFT_VERSION = 5.0; 626 | TARGETED_DEVICE_FAMILY = "1,2"; 627 | TEST_TARGET_NAME = iosApp; 628 | }; 629 | name = Debug; 630 | }; 631 | 7555FFAD242A565B00829871 /* Release */ = { 632 | isa = XCBuildConfiguration; 633 | buildSettings = { 634 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 635 | CODE_SIGN_STYLE = Automatic; 636 | INFOPLIST_FILE = iosAppUITests/Info.plist; 637 | LD_RUNPATH_SEARCH_PATHS = ( 638 | "$(inherited)", 639 | "@executable_path/Frameworks", 640 | "@loader_path/Frameworks", 641 | ); 642 | PRODUCT_BUNDLE_IDENTIFIER = orgIdentifier.iosAppUITests; 643 | PRODUCT_NAME = "$(TARGET_NAME)"; 644 | SWIFT_VERSION = 5.0; 645 | TARGETED_DEVICE_FAMILY = "1,2"; 646 | TEST_TARGET_NAME = iosApp; 647 | }; 648 | name = Release; 649 | }; 650 | /* End XCBuildConfiguration section */ 651 | 652 | /* Begin XCConfigurationList section */ 653 | 7555FF76242A565900829871 /* Build configuration list for PBXProject "iosApp" */ = { 654 | isa = XCConfigurationList; 655 | buildConfigurations = ( 656 | 7555FFA3242A565B00829871 /* Debug */, 657 | 7555FFA4242A565B00829871 /* Release */, 658 | ); 659 | defaultConfigurationIsVisible = 0; 660 | defaultConfigurationName = Release; 661 | }; 662 | 7555FFA5242A565B00829871 /* Build configuration list for PBXNativeTarget "iosApp" */ = { 663 | isa = XCConfigurationList; 664 | buildConfigurations = ( 665 | 7555FFA6242A565B00829871 /* Debug */, 666 | 7555FFA7242A565B00829871 /* Release */, 667 | ); 668 | defaultConfigurationIsVisible = 0; 669 | defaultConfigurationName = Release; 670 | }; 671 | 7555FFA8242A565B00829871 /* Build configuration list for PBXNativeTarget "iosAppTests" */ = { 672 | isa = XCConfigurationList; 673 | buildConfigurations = ( 674 | 7555FFA9242A565B00829871 /* Debug */, 675 | 7555FFAA242A565B00829871 /* Release */, 676 | ); 677 | defaultConfigurationIsVisible = 0; 678 | defaultConfigurationName = Release; 679 | }; 680 | 7555FFAB242A565B00829871 /* Build configuration list for PBXNativeTarget "iosAppUITests" */ = { 681 | isa = XCConfigurationList; 682 | buildConfigurations = ( 683 | 7555FFAC242A565B00829871 /* Debug */, 684 | 7555FFAD242A565B00829871 /* Release */, 685 | ); 686 | defaultConfigurationIsVisible = 0; 687 | defaultConfigurationName = Release; 688 | }; 689 | /* End XCConfigurationList section */ 690 | }; 691 | rootObject = 7555FF73242A565900829871 /* Project object */; 692 | } 693 | -------------------------------------------------------------------------------- /iosApp/iosApp/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | @UIApplicationMain 4 | class AppDelegate: UIResponder, UIApplicationDelegate { 5 | 6 | 7 | 8 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 9 | 10 | setupNavigationBar() 11 | return true 12 | } 13 | 14 | // MARK: UISceneSession Lifecycle 15 | 16 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 17 | // Called when a new scene session is being created. 18 | // Use this method to select a configuration to create the new scene with. 19 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 20 | } 21 | 22 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 23 | // Called when the user discards a scene session. 24 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 25 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 26 | } 27 | 28 | 29 | } 30 | 31 | extension AppDelegate { 32 | 33 | private func setupNavigationBar() { 34 | 35 | UINavigationBar.appearance().backItem?.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil) 36 | UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] 37 | UINavigationBar.appearance().tintColor = .white 38 | UINavigationBar.appearance().isTranslucent = false 39 | UINavigationBar.appearance().barTintColor = color6200EA 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /iosApp/iosApp/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /iosApp/iosApp/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 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 | -------------------------------------------------------------------------------- /iosApp/iosApp/Common Files/AppConstants.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppConstants.swift 3 | // iosApp 4 | // 5 | // Created by mac-0009 on 05/11/20. 6 | // Copyright © 2020 orgName. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | let color6200EA = #colorLiteral(red: 0.3843137255, green: 0, blue: 0.9176470588, alpha: 1) 12 | -------------------------------------------------------------------------------- /iosApp/iosApp/ContentView.swift: -------------------------------------------------------------------------------- 1 | import SwiftUI 2 | import shared 3 | 4 | 5 | struct ContentView: View { 6 | var body: some View { 7 | Text("Hello World") 8 | } 9 | } 10 | 11 | struct ContentView_Previews: PreviewProvider { 12 | static var previews: some View { 13 | ContentView() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /iosApp/iosApp/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UIApplicationSceneManifest 24 | 25 | UIApplicationSupportsMultipleScenes 26 | 27 | UISceneConfigurations 28 | 29 | UIWindowSceneSessionRoleApplication 30 | 31 | 32 | UISceneConfigurationName 33 | Default Configuration 34 | UISceneDelegateClassName 35 | $(PRODUCT_MODULE_NAME).SceneDelegate 36 | 37 | 38 | 39 | 40 | UILaunchStoryboardName 41 | LaunchScreen 42 | UIRequiredDeviceCapabilities 43 | 44 | armv7 45 | 46 | UIStatusBarStyle 47 | UIStatusBarStyleLightContent 48 | UISupportedInterfaceOrientations 49 | 50 | UIInterfaceOrientationPortrait 51 | UIInterfaceOrientationLandscapeLeft 52 | UIInterfaceOrientationLandscapeRight 53 | 54 | UISupportedInterfaceOrientations~ipad 55 | 56 | UIInterfaceOrientationPortrait 57 | UIInterfaceOrientationPortraitUpsideDown 58 | UIInterfaceOrientationLandscapeLeft 59 | UIInterfaceOrientationLandscapeRight 60 | 61 | UIViewControllerBasedStatusBarAppearance 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /iosApp/iosApp/Preview Content/Preview Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /iosApp/iosApp/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | import SwiftUI 3 | 4 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 5 | 6 | var window: UIWindow? 7 | 8 | 9 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 10 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 11 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 12 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 13 | 14 | guard let windowScene = (scene as? UIWindowScene) else { return } 15 | 16 | window = UIWindow(windowScene: windowScene) 17 | window?.rootViewController = UINavigationController(rootViewController: ViewController()) 18 | window?.makeKeyAndVisible() 19 | } 20 | 21 | func sceneDidDisconnect(_ scene: UIScene) { 22 | // Called as the scene is being released by the system. 23 | // This occurs shortly after the scene enters the background, or when its session is discarded. 24 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 25 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 26 | } 27 | 28 | func sceneDidBecomeActive(_ scene: UIScene) { 29 | // Called when the scene has moved from an inactive state to an active state. 30 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 31 | } 32 | 33 | func sceneWillResignActive(_ scene: UIScene) { 34 | // Called when the scene will move from an active state to an inactive state. 35 | // This may occur due to temporary interruptions (ex. an incoming phone call). 36 | } 37 | 38 | func sceneWillEnterForeground(_ scene: UIScene) { 39 | // Called as the scene transitions from the background to the foreground. 40 | // Use this method to undo the changes made on entering the background. 41 | } 42 | 43 | func sceneDidEnterBackground(_ scene: UIScene) { 44 | // Called as the scene transitions from the foreground to the background. 45 | // Use this method to save data, release shared resources, and store enough scene-specific state information 46 | // to restore the scene back to its current state. 47 | } 48 | 49 | 50 | } 51 | 52 | -------------------------------------------------------------------------------- /iosApp/iosApp/TableViewCell/EmployeeTblVCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EmployeeTblVCell.swift 3 | // iosApp 4 | // 5 | // Created by mac-0009 on 04/11/20. 6 | // Copyright © 2020 orgName. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import shared 11 | 12 | class EmployeeTblVCell: UITableViewCell { 13 | 14 | @IBOutlet weak private var lblEmplyeeName: UILabel! 15 | @IBOutlet weak private var lblEmployeeAge: UILabel! 16 | @IBOutlet weak private var lblEmployeeSalary: UILabel! 17 | 18 | override func awakeFromNib() { 19 | super.awakeFromNib() 20 | } 21 | 22 | override func setSelected(_ selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | } 25 | 26 | } 27 | 28 | 29 | // MARK: - 30 | // MARK: - Configure Cell 31 | 32 | extension EmployeeTblVCell { 33 | 34 | func configureCellData(with employee: EmployeeDataItem) { 35 | 36 | lblEmplyeeName.text = "Name: " + employee.employeeName 37 | lblEmployeeAge.text = "Age: " + employee.employeeAge 38 | lblEmployeeSalary.text = "Salary: $ \(employee.employeeSalary)" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /iosApp/iosApp/TableViewCell/EmployeeTblVCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 36 | 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 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /iosApp/iosApp/ViewController/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // iosApp 4 | // 5 | // Created by mac-0009 on 04/11/20. 6 | // Copyright © 2020 orgName. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import shared 11 | 12 | class ViewController: UIViewController { 13 | 14 | // IBOutlets 15 | 16 | @IBOutlet weak private var tblvEmployee: UITableView! { 17 | didSet { 18 | tblvEmployee.contentInset = UIEdgeInsets(top: 15, left: 0, bottom: 0, right: 0) 19 | } 20 | } 21 | @IBOutlet weak private var activityIndicator: UIActivityIndicatorView! 22 | @IBOutlet weak private var lblNoDataFound: UILabel! 23 | 24 | // Variables 25 | 26 | private var arrEmployee = [EmployeeDataItem]() 27 | private let refreshContol = UIRefreshControl() 28 | 29 | // ViewController Life Cycle 30 | 31 | override func viewDidLoad() { 32 | super.viewDidLoad() 33 | initialize() 34 | } 35 | 36 | deinit { 37 | 38 | } 39 | } 40 | 41 | 42 | // MARK: - 43 | // MARK: - General Methods 44 | 45 | extension ViewController { 46 | 47 | private func initialize() { 48 | 49 | self.title = "KMM" 50 | 51 | setupTableView() 52 | setupRefreshControl() 53 | 54 | loadEmployees() 55 | } 56 | 57 | private func setupTableView() { 58 | tblvEmployee.register(UINib(nibName: "EmployeeTblVCell", bundle: nil), forCellReuseIdentifier: "EmployeeTblVCell") 59 | } 60 | 61 | private func setupRefreshControl() { 62 | 63 | refreshContol.tintColor = color6200EA 64 | refreshContol.addTarget(self, action: #selector(pullToRefresh), for: .valueChanged) 65 | tblvEmployee.refreshControl = refreshContol 66 | } 67 | } 68 | 69 | 70 | // MARK: - 71 | // MARK: - TableView Delegate & DataSource 72 | 73 | extension ViewController: UITableViewDelegate, UITableViewDataSource { 74 | 75 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 76 | arrEmployee.count 77 | } 78 | 79 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 80 | 81 | if let cell = tableView.dequeueReusableCell(withIdentifier: "EmployeeTblVCell") as? EmployeeTblVCell { 82 | 83 | let employee = arrEmployee[indexPath.row] 84 | cell.configureCellData(with: employee) 85 | return cell 86 | } 87 | 88 | return UITableViewCell() 89 | } 90 | 91 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 92 | print(arrEmployee[indexPath.row]) 93 | } 94 | } 95 | 96 | 97 | // MARK: - 98 | // MARK: - API Activity 99 | 100 | extension ViewController { 101 | 102 | @objc 103 | private func pullToRefresh() { 104 | self.loadEmployees(isLoaderRequire: false, forceReload: true) 105 | } 106 | 107 | private func loadEmployees(isLoaderRequire: Bool = true, forceReload: Bool = false) { 108 | 109 | let sdk = EmployeeSDK(databaseDriverFactory: DatabaseDriverFactory()) 110 | 111 | if isLoaderRequire { 112 | activityIndicator.startAnimating() 113 | } 114 | 115 | sdk.getEmployees(forceReload: forceReload) { (employees, error) in 116 | 117 | self.activityIndicator.stopAnimating() 118 | self.refreshContol.endRefreshing() 119 | 120 | if let employees = employees { 121 | 122 | self.tblvEmployee.isHidden = false 123 | 124 | self.arrEmployee.removeAll() 125 | self.arrEmployee = employees 126 | self.tblvEmployee.reloadData() 127 | 128 | } else { 129 | 130 | self.lblNoDataFound.isHidden = false 131 | print(error?.localizedDescription ?? "error") 132 | } 133 | } 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /iosApp/iosApp/ViewController/ViewController.xib: -------------------------------------------------------------------------------- 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 | 33 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /iosApp/iosApp/main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /iosApp/iosAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iosApp/iosAppTests/iosAppTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import iosApp 3 | 4 | class iosAppTests: XCTestCase { 5 | 6 | override func setUp() { 7 | // Put setup code here. This method is called before the invocation of each test method in the class. 8 | } 9 | 10 | override func tearDown() { 11 | // Put teardown code here. This method is called after the invocation of each test method in the class. 12 | } 13 | 14 | func testExample() { 15 | // This is an example of a functional test case. 16 | // Use XCTAssert and related functions to verify your tests produce the correct results. 17 | } 18 | 19 | func testPerformanceExample() { 20 | // This is an example of a performance test case. 21 | self.measure { 22 | // Put the code you want to measure the time of here. 23 | } 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /iosApp/iosAppUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /iosApp/iosAppUITests/iosAppUITests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | class appNameUITests: XCTestCase { 4 | 5 | override func setUp() { 6 | // Put setup code here. This method is called before the invocation of each test method in the class. 7 | 8 | // In UI tests it is usually best to stop immediately when a failure occurs. 9 | continueAfterFailure = false 10 | 11 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 12 | } 13 | 14 | override func tearDown() { 15 | // Put teardown code here. This method is called after the invocation of each test method in the class. 16 | } 17 | 18 | func testExample() { 19 | // UI tests must launch the application that they test. 20 | let app = XCUIApplication() 21 | app.launch() 22 | 23 | // Use recording to get started writing UI tests. 24 | // Use XCTAssert and related functions to verify your tests produce the correct results. 25 | } 26 | 27 | func testLaunchPerformance() { 28 | if #available(macOS 10.15, iOS 13.0, tvOS 13.0, *) { 29 | // This measures how long it takes to launch your application. 30 | measure(metrics: [XCTOSSignpostMetric.applicationLaunch]) { 31 | XCUIApplication().launch() 32 | } 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /media/kotlin-multiplaform-mobile-iOS.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mindinventory/Kotlin-multiplatform-sample/fd4e175b62404b92f825f9ef2ff07540dcffd58a/media/kotlin-multiplaform-mobile-iOS.gif -------------------------------------------------------------------------------- /media/kotlin-multiplaform-mobile.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mindinventory/Kotlin-multiplatform-sample/fd4e175b62404b92f825f9ef2ff07540dcffd58a/media/kotlin-multiplaform-mobile.gif -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | gradlePluginPortal() 4 | google() 5 | jcenter() 6 | mavenCentral() 7 | } 8 | resolutionStrategy { 9 | eachPlugin { 10 | if (requested.id.namespace == "com.android" || requested.id.name == "kotlin-android-extensions") { 11 | useModule("com.android.tools.build:gradle:4.0.1") 12 | } 13 | } 14 | } 15 | } 16 | rootProject.name = "Kotlin-multiplatform-sample" 17 | 18 | 19 | include(":androidApp") 20 | include(":shared") 21 | 22 | -------------------------------------------------------------------------------- /shared/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget 2 | 3 | plugins { 4 | kotlin("multiplatform") 5 | id("com.android.library") 6 | id("kotlin-android-extensions") 7 | kotlin("plugin.serialization") 8 | id("com.squareup.sqldelight") 9 | } 10 | group = "com.mindinventory.kmm" 11 | version = "1.0-SNAPSHOT" 12 | 13 | repositories { 14 | gradlePluginPortal() 15 | google() 16 | jcenter() 17 | mavenCentral() 18 | } 19 | 20 | val coroutinesVersion = "1.3.9-native-mt" 21 | val serializationVersion = "1.0.0-RC" 22 | val ktorVersion = "1.4.0" 23 | val sqlDelightVersion: String by project 24 | 25 | kotlin { 26 | android() 27 | ios { 28 | binaries { 29 | framework { 30 | baseName = "shared" 31 | } 32 | } 33 | } 34 | sourceSets { 35 | val commonMain by getting { 36 | dependencies{ 37 | implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") 38 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion") 39 | implementation("io.ktor:ktor-client-serialization:$ktorVersion") 40 | // it is expected interfaces 41 | implementation("io.ktor:ktor-client-core:$ktorVersion") 42 | implementation("com.squareup.sqldelight:runtime:$sqlDelightVersion") 43 | } 44 | } 45 | val commonTest by getting { 46 | dependencies { 47 | implementation(kotlin("test-common")) 48 | implementation(kotlin("test-annotations-common")) 49 | } 50 | } 51 | val androidMain by getting { 52 | dependencies { 53 | implementation("com.google.android.material:material:1.2.1") 54 | // it is actual platform implementations 55 | implementation("io.ktor:ktor-client-android:$ktorVersion") 56 | implementation("com.squareup.sqldelight:android-driver:$sqlDelightVersion") 57 | } 58 | } 59 | val androidTest by getting { 60 | dependencies { 61 | implementation(kotlin("test-junit")) 62 | implementation("junit:junit:4.12") 63 | } 64 | } 65 | val iosMain by getting{ 66 | dependencies{ 67 | // it is actual platform implementations 68 | implementation("io.ktor:ktor-client-ios:$ktorVersion") 69 | implementation("com.squareup.sqldelight:native-driver:$sqlDelightVersion") 70 | } 71 | } 72 | val iosTest by getting 73 | } 74 | } 75 | android { 76 | compileSdkVersion(29) 77 | sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml") 78 | defaultConfig { 79 | minSdkVersion(24) 80 | targetSdkVersion(29) 81 | versionCode = 1 82 | versionName = "1.0" 83 | } 84 | buildTypes { 85 | getByName("release") { 86 | isMinifyEnabled = false 87 | } 88 | } 89 | } 90 | sqldelight { 91 | // database configuration 92 | database("AppDatabase") { 93 | packageName = "com.mindinventory.kmm.shared.cache" 94 | } 95 | } 96 | val packForXcode by tasks.creating(Sync::class) { 97 | group = "build" 98 | val mode = System.getenv("CONFIGURATION") ?: "DEBUG" 99 | val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator" 100 | val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64" 101 | val framework = kotlin.targets.getByName(targetName).binaries.getFramework(mode) 102 | inputs.property("mode", mode) 103 | dependsOn(framework.linkTask) 104 | val targetDir = File(buildDir, "xcode-frameworks") 105 | from({ framework.outputDirectory }) 106 | into(targetDir) 107 | } 108 | tasks.getByName("build").dependsOn(packForXcode) -------------------------------------------------------------------------------- /shared/src/androidMain/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /shared/src/androidMain/kotlin/com/mindinventory/kmm/shared/cache/DatabaseDriverFactory.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.cache 2 | 3 | import android.content.Context 4 | import com.squareup.sqldelight.android.AndroidSqliteDriver 5 | import com.squareup.sqldelight.db.SqlDriver 6 | 7 | // here we are providing SqlDriver of Android - a native implementation 8 | actual class DatabaseDriverFactory(private val context: Context) { 9 | actual fun createDriver(): SqlDriver { 10 | return AndroidSqliteDriver(AppDatabase.Schema, context, "employee.db") 11 | } 12 | } -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/com/mindinventory/kmm/shared/EmployeeSDK.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared 2 | 3 | import com.mindinventory.kmm.shared.cache.Database 4 | import com.mindinventory.kmm.shared.cache.DatabaseDriverFactory 5 | import com.mindinventory.kmm.shared.entity.EmployeeDataItem 6 | import com.mindinventory.kmm.shared.network.EmployeeApi 7 | 8 | // this is the main class to interact with your shared module code 9 | class EmployeeSDK(databaseDriverFactory: DatabaseDriverFactory) { 10 | private val database = Database(databaseDriverFactory) 11 | private val api = EmployeeApi() 12 | 13 | @Throws(Exception::class) 14 | suspend fun getEmployees(forceReload: Boolean): List { 15 | val cachedEmployee = database.getAllEmployee() 16 | return if (cachedEmployee.isNotEmpty() && !forceReload) { 17 | cachedEmployee 18 | } else { 19 | api.getAllEmployee().data.also { 20 | database.clearDatabase() 21 | database.createEmployee(it) 22 | } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/com/mindinventory/kmm/shared/cache/Database.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.cache 2 | 3 | import com.mindinventory.kmm.shared.entity.EmployeeDataItem 4 | 5 | internal class Database(databaseDriverFactory: DatabaseDriverFactory) { 6 | // initialising database 7 | private val database = AppDatabase(databaseDriverFactory.createDriver()) 8 | private val dbQuery = database.appDatabaseQueries 9 | 10 | internal fun clearDatabase() { 11 | dbQuery.transaction { 12 | dbQuery.deleteAllEmployee() 13 | } 14 | } 15 | 16 | internal fun getAllEmployee(): List { 17 | return dbQuery.selectAllEmployee(::mapEmployeeSelecting).executeAsList() 18 | } 19 | 20 | private fun mapEmployeeSelecting( 21 | id: Long, 22 | employee_name: String, 23 | employee_salary: Int, 24 | employee_age: String, 25 | profile_image: String 26 | ): EmployeeDataItem { 27 | return EmployeeDataItem( 28 | profileImage = profile_image, 29 | employeeName = employee_name, 30 | employeeSalary = employee_salary, 31 | id = id.toInt(), 32 | employeeAge = employee_age 33 | ) 34 | } 35 | 36 | internal fun createEmployee(employee: List) { 37 | dbQuery.transaction { 38 | repeat(employee.size) { insertEmployee(employee[it]) } 39 | } 40 | } 41 | 42 | private fun insertEmployee(emp: EmployeeDataItem) { 43 | dbQuery.insertLaunch( 44 | emp.id.toLong(), 45 | emp.employeeName, 46 | emp.employeeSalary, 47 | emp.employeeAge, 48 | emp.profileImage 49 | ) 50 | } 51 | } -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/com/mindinventory/kmm/shared/cache/DatabaseDriverFactory.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.cache 2 | 3 | import com.squareup.sqldelight.db.SqlDriver 4 | 5 | // this expects native implementations for SqlDriver 6 | expect class DatabaseDriverFactory { 7 | fun createDriver(): SqlDriver 8 | } -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/com/mindinventory/kmm/shared/entity/Employee.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.entity 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | 6 | // models according to API response 7 | 8 | @Serializable 9 | data class Employee( 10 | 11 | @SerialName("data") 12 | val data: List, 13 | 14 | @SerialName("status") 15 | val status: String? = null 16 | ) 17 | 18 | @Serializable 19 | data class EmployeeDataItem( 20 | 21 | @SerialName("profile_image") 22 | val profileImage: String, 23 | 24 | @SerialName("employee_name") 25 | val employeeName: String, 26 | 27 | @SerialName("employee_salary") 28 | val employeeSalary: Int, 29 | 30 | @SerialName("id") 31 | val id: Int, 32 | 33 | @SerialName("employee_age") 34 | val employeeAge: String 35 | ){ 36 | fun getSalaryInString() = "$ $employeeSalary" 37 | } 38 | -------------------------------------------------------------------------------- /shared/src/commonMain/kotlin/com/mindinventory/kmm/shared/network/EmployeeApi.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.network 2 | 3 | import com.mindinventory.kmm.shared.entity.Employee 4 | import io.ktor.client.* 5 | import io.ktor.client.features.json.* 6 | import io.ktor.client.features.json.serializer.* 7 | import io.ktor.client.request.* 8 | 9 | object Api { 10 | // API url, you can even define with separation like base url, api path and api version 11 | const val API_ENDPOINT = "https://run.mocky.io/v3/4e809584-adb3-4b70-bfbb-b8843d3764e1" 12 | } 13 | 14 | class EmployeeApi { 15 | 16 | private val httpClient = HttpClient { 17 | install(JsonFeature) { 18 | val json = kotlinx.serialization.json.Json { ignoreUnknownKeys = true } 19 | serializer = KotlinxSerializer(json) 20 | } 21 | } 22 | 23 | suspend fun getAllEmployee(): Employee { 24 | // simple get method API call, you can use post, delete etc. as per needs 25 | return httpClient.get(Api.API_ENDPOINT) 26 | } 27 | } -------------------------------------------------------------------------------- /shared/src/commonMain/sqldelight/com/mindinventory/kmm/shared/cache/AppDatabase.sq: -------------------------------------------------------------------------------- 1 | CREATE TABLE Employee ( 2 | id INTEGER NOT NULL, 3 | employee_name TEXT NOT NULL, 4 | employee_salary INTEGER AS Int NOT NULL DEFAULT 0, 5 | employee_age TEXT NOT NULL DEFAULT 0, 6 | profile_image TEXT NOT NULL 7 | ); 8 | 9 | insertLaunch: 10 | INSERT INTO Employee(id, employee_name, employee_salary, employee_age, profile_image) 11 | VALUES(?, ?, ?, ?, ?); 12 | 13 | selectEmployeeByName: 14 | SELECT * FROM Employee 15 | WHERE employee_name = ?; 16 | 17 | selectEmployeeByID: 18 | SELECT * FROM Employee 19 | WHERE id = ?; 20 | 21 | selectAllEmployee: 22 | SELECT * FROM Employee; 23 | 24 | deleteAllEmployee: 25 | DELETE FROM Employee; -------------------------------------------------------------------------------- /shared/src/commonMain/sqldelight/com/mindinventory/kmm/shared/cache/AppDatabaseReadMe.txt: -------------------------------------------------------------------------------- 1 | "AppDatabase.sq" file contains all the queries regarding your database transactions -------------------------------------------------------------------------------- /shared/src/iosMain/kotlin/com/mindinventory/kmm/shared/cache/DatabaseDriverFactory.kt: -------------------------------------------------------------------------------- 1 | package com.mindinventory.kmm.shared.cache 2 | 3 | import com.squareup.sqldelight.db.SqlDriver 4 | import com.squareup.sqldelight.drivers.native.NativeSqliteDriver 5 | 6 | // here we are providing SqlDriver of iOS - a native implementation 7 | actual class DatabaseDriverFactory { 8 | actual fun createDriver(): SqlDriver { 9 | return NativeSqliteDriver(AppDatabase.Schema, "employee.db") 10 | } 11 | } --------------------------------------------------------------------------------