├── .gitignore
├── .gitlab-ci.yml
├── Code
├── Client
│ ├── .gitignore
│ ├── Android
│ │ ├── .gitignore
│ │ ├── android-client-shared
│ │ │ ├── .gitignore
│ │ │ ├── build.gradle.kts
│ │ │ ├── proguard-rules.pro
│ │ │ └── src
│ │ │ │ ├── androidAndroidTest
│ │ │ │ └── kotlin
│ │ │ │ │ └── org
│ │ │ │ │ └── chrishatton
│ │ │ │ │ └── example
│ │ │ │ │ └── common
│ │ │ │ │ └── ExampleInstrumentedTest.java
│ │ │ │ ├── androidMain
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── org
│ │ │ │ │ │ └── chrishatton
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── common
│ │ │ │ │ │ ├── FirstFragment.kt
│ │ │ │ │ │ └── package.kt
│ │ │ │ └── res
│ │ │ │ │ ├── layout
│ │ │ │ │ └── fragment_first.xml
│ │ │ │ │ └── values
│ │ │ │ │ └── strings.xml
│ │ │ │ └── androidTest
│ │ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ └── common
│ │ │ │ └── ExampleUnitTest.kt
│ │ ├── build.gradle.kts
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── mobile
│ │ │ ├── .gitignore
│ │ │ ├── build.gradle.kts
│ │ │ ├── proguard-rules.pro
│ │ │ └── src
│ │ │ │ ├── androidAndroidTest
│ │ │ │ └── kotlin
│ │ │ │ │ └── example
│ │ │ │ │ └── ExampleInstrumentedTest.kt
│ │ │ │ ├── androidMain
│ │ │ │ ├── AndroidManifest.xml
│ │ │ │ ├── kotlin
│ │ │ │ │ └── org
│ │ │ │ │ │ └── chrishatton
│ │ │ │ │ │ └── example
│ │ │ │ │ │ └── mobile
│ │ │ │ │ │ └── MainActivity.kt
│ │ │ │ └── res
│ │ │ │ │ ├── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ │ ├── drawable
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ │ │ ├── layout
│ │ │ │ │ └── activity_main.xml
│ │ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.png
│ │ │ │ │ └── ic_launcher_round.png
│ │ │ │ │ └── values
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ └── styles.xml
│ │ │ │ └── androidTest
│ │ │ │ └── kotlin
│ │ │ │ └── example
│ │ │ │ └── ExampleUnitTest.kt
│ │ ├── settings.gradle.kts
│ │ └── tv
│ │ │ ├── .gitignore
│ │ │ ├── build.gradle.kts
│ │ │ ├── proguard-rules.pro
│ │ │ └── src
│ │ │ └── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── kotlin
│ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ └── tv
│ │ │ │ └── MainActivity.kt
│ │ │ └── res
│ │ │ ├── drawable
│ │ │ ├── app_icon_your_company.png
│ │ │ ├── default_background.xml
│ │ │ └── movie.png
│ │ │ ├── layout
│ │ │ ├── activity_details.xml
│ │ │ └── activity_main.xml
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ └── values
│ │ │ ├── colors.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ ├── Browser
│ │ ├── build.gradle.kts
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ └── settings.gradle.kts
│ ├── Desktop
│ │ ├── build.gradle.kts
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ │ └── wrapper
│ │ │ │ ├── gradle-wrapper.jar
│ │ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ ├── gradlew.bat
│ │ ├── settings.gradle.kts
│ │ └── src
│ │ │ ├── javafxMain
│ │ │ ├── kotlin
│ │ │ │ └── org
│ │ │ │ │ └── chrishatton
│ │ │ │ │ └── example
│ │ │ │ │ ├── ExampleApp.kt
│ │ │ │ │ └── NoteListView.kt
│ │ │ └── resources
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ ├── NewNoteView.fxml
│ │ │ │ ├── NoteListCell.fxml
│ │ │ │ └── NoteListView.fxml
│ │ │ └── test
│ │ │ └── kotlin
│ │ │ └── sample
│ │ │ └── SampleTestsJavafx.kt
│ ├── Shared
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ ├── androidMain
│ │ │ ├── AndroidManifest.xml
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ ├── ExampleClient.kt
│ │ │ │ └── Platform.kt
│ │ │ ├── androidTest
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ └── package.kt
│ │ │ ├── commonMain
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ ├── ExampleClient.kt
│ │ │ │ ├── Platform.kt
│ │ │ │ └── ui
│ │ │ │ ├── FirstContract.kt
│ │ │ │ └── FirstPresenter.kt
│ │ │ ├── commonTest
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ └── CommonPlatformTests.kt
│ │ │ ├── iosMain
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ ├── ExampleClient.kt
│ │ │ │ └── Platform.kt
│ │ │ ├── javafxMain
│ │ │ └── kotlin
│ │ │ │ └── org
│ │ │ │ └── chrishatton
│ │ │ │ └── example
│ │ │ │ ├── ExampleClient.kt
│ │ │ │ └── Platform.kt
│ │ │ └── javafxTest
│ │ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── package.kt
│ ├── build.gradle.kts
│ ├── client-shared.build.gradle.kts
│ ├── client-shared.settings.gradle.kts
│ └── iOS
│ │ ├── Example.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ ├── xcshareddata
│ │ │ │ └── IDEWorkspaceChecks.plist
│ │ │ └── xcuserdata
│ │ │ │ └── Chris.xcuserdatad
│ │ │ │ └── xcschemes
│ │ │ │ └── xcschememanagement.plist
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Example.xcscheme
│ │ ├── Example
│ │ ├── Assets.xcassets
│ │ │ └── AppIcon.appiconset
│ │ │ │ └── Contents.json
│ │ ├── Base.lproj
│ │ │ ├── LaunchScreen.storyboard
│ │ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ ├── build.gradle.kts
│ │ └── src
│ │ │ └── iosMain
│ │ │ └── kotlin
│ │ │ ├── example
│ │ │ ├── AppDelegate.kt
│ │ │ ├── BaseViewAdapter.kt
│ │ │ └── FirstViewController.kt
│ │ │ └── main.kt
│ │ └── SupportingFiles
│ │ ├── build.gradle.kts
│ │ ├── gradle.properties
│ │ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ │ ├── gradlew
│ │ └── settings.gradle.kts
├── README.md
├── Server
│ ├── .gitignore
│ ├── build.gradle.kts
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ ├── gradle-wrapper.jar
│ │ │ └── gradle-wrapper.properties
│ ├── gradlew
│ ├── gradlew.bat
│ ├── renamePackage.kts
│ ├── settings.gradle.kts
│ ├── src
│ │ ├── main
│ │ │ ├── kotlin
│ │ │ │ └── example
│ │ │ │ │ └── Application.kt
│ │ │ └── resources
│ │ │ │ ├── application.conf
│ │ │ │ └── logback.xml
│ │ └── test
│ │ │ └── kotlin
│ │ │ └── example
│ │ │ └── ApplicationTest.kt
│ └── webapp
│ │ └── WEB-INF
│ │ └── web.xml
├── Shared
│ ├── .gitignore
│ ├── build.gradle.kts
│ └── src
│ │ ├── androidMain
│ │ ├── AndroidManifest.xml
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ └── UUID.kt
│ │ ├── androidTest
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── SampleTestsJVM.kt
│ │ ├── browserMain
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ └── UUID.kt
│ │ ├── commonMain
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ ├── Person.kt
│ │ │ ├── UUID.kt
│ │ │ └── api
│ │ │ └── CRUD.kt
│ │ ├── commonTest
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── SharedCommonTests.kt
│ │ ├── iosMain
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ └── UUID.kt
│ │ ├── iosTest
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── SharediOSTests.kt
│ │ ├── javafxMain
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ └── UUID.kt
│ │ ├── javafxTest
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ ├── SampleTestsJVM.kt
│ │ │ └── package.kt
│ │ ├── serverMain
│ │ └── kotlin
│ │ │ └── org
│ │ │ └── chrishatton
│ │ │ └── example
│ │ │ └── model
│ │ │ └── UUID.kt
│ │ └── serverTest
│ │ └── kotlin
│ │ └── org
│ │ └── chrishatton
│ │ └── example
│ │ ├── SampleTestsJVM.kt
│ │ └── package.kt
├── build.gradle.kts
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── local.properties.template
├── renamePackage.kts
├── settings.gradle.kts
├── shared.gradle.kts
├── shared.properties
└── shared.settings.gradle.kts
├── LICENSE.txt
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | Code/Client/app/build
2 | Code/Shared/build
3 | Code/Client/iOS/BM/build
4 | Code/Client/Common/build
5 | Code/Client/iOS/SupportingFiles/.gradle
6 | Code/Client/iOS/BM.xcodeproj/xcuserdata
7 | Code/Client/iOS/BM.xcodeproj/project.xcworkspace/xcuserdata
8 | Code/Client/Common/.gradle
9 | Code/.gradle
10 | Code/Client/Desktop/.gradle
11 | Code/Client/iOS/BM.xcodeproj/project.xcworkspace/xcshareddata
12 | *.iml
13 | Code/Client/iOS/Example.xcodeproj/xcuserdata
14 | Code/Client/iOS/Example/build
15 | Code/Client/iOS/Example.xcodeproj/project.xcworkspace/xcuserdata
16 | Code/Client/Desktop/build
17 | Code/Client/iOS/Example/.gradle
18 | Code/Build/buildSrc/.gradle
19 | Code/Build/buildSrc/.gradle
20 | Code/Client/Common/multi-mvp/.gradle
21 | Code/Client/Common/multi-mvp/build
22 | Code/Client/Shared/.gradle
23 | Code/Client/Shared/build
24 | Code/Lib/multi-mvp/.gradle
25 | Code/Lib/multi-mvp/build
26 | Code/Lib/coroutines-ui/.gradle
27 | Code/Lib/coroutines-ui/build
28 | Code/Client/iOS/SupportingFiles/build
29 | Code/Build
30 | Code/Client/Android/build-cache
31 | Code/Server/build-cache
32 | Code/Client/Desktop/build-cache
33 | Code/Client/iOS/SupportingFiles/build-cache
34 | Code/Lib/coroutines-ui/build
35 | Code/local.properties
36 | Code/Client/Browser/.gradle
37 | Code/Client/Browser/build
38 |
--------------------------------------------------------------------------------
/.gitlab-ci.yml:
--------------------------------------------------------------------------------
1 |
2 | variables:
3 | GRADLE_OPTS: "-Dorg.gradle.daemon=false"
4 |
5 | before_script:
6 | - export GRADLE_USER_HOME=`pwd`/.gradle
7 |
8 | stages:
9 | - wakeBuildMachine
10 | - buildAndTest
11 | - publishLibs
12 | - deploy
13 | - shutdownBuildMachine
14 |
15 | wakeBuildMachine:
16 | stage: wakeBuildMachine
17 | tags:
18 | - small
19 | script:
20 | - ~/wakeRumpus.sh
21 |
22 | shutdownBuildMachine:
23 | stage: shutdownBuildMachine
24 | when: always
25 | tags:
26 | - small
27 | script:
28 | - ~/shutdownRumpus.sh
29 |
30 | buildAndTest:
31 | stage: buildAndTest
32 | tags:
33 | - large
34 | script:
35 | - cd Code
36 | - cp ~/Properties/MultiplatformTemplate/local.properties .
37 | - ./gradlew buildAndTestApp
38 | cache:
39 | key: "$CI_COMMIT_REF_NAME-App"
40 | policy: pull-push
41 | paths:
42 | - .gradle/wrapper
43 | - .gradle/caches
44 | - Code/Server/build
45 | - Code/Shared/build
46 | - Code/Lib/multi-mvp/build
47 | - Code/Client/Desktop/build
48 | - Code/Client/Shared/build
49 | - Code/Client/iOS/Example/build
50 | - Code/Client/iOS/SupportingFiles/build
51 | - Code/Client/Android/tv/build
52 | - Code/Client/Android/android-client-shared/build
53 | - Code/Client/Android/mobile/build
54 | - Code/Client/Android/build
55 | artifacts:
56 | name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
57 | paths:
58 | - Code/Server/build/*.war
59 | - Code/Client/Desktop/build/*.zip
60 | - Code/Client/Android/tv/build/outputs/apk/**/*.apk
61 | - Code/Client/Android/mobile/build/outputs/apk/**/*.apk
62 | - Code/Client/iOS/Example/build/**/*.ipa
63 | # reports:
64 | # junit:
65 | # - Code/Server/build/reports/**/*.xml
66 | # - Code/Shared/build/reports/**/*.xml
67 | # - Code/Lib/multi-mvp/build/reports/**/*.xml
68 | # - Code/Client/Desktop/build/reports/**/*.xml
69 | # - Code/Client/Shared/build/reports/**/*.xml
70 | # - Code/Client/Android/android-client-shared/build/reports/**/*.xml
71 | # - Code/Client/Android/mobile/build/reports/**/*.xml
72 |
73 | publishLibs:
74 | tags:
75 | - large
76 | only:
77 | - master
78 | stage: publishLibs
79 | script:
80 | - cd Code
81 | - cp ~/Properties/MultiplatformTemplate/local.properties .
82 | - ./gradlew publishLibs
83 | cache:
84 | key: "${CI_COMMIT_REF_NAME}-App"
85 | policy: pull
86 | paths:
87 | - Code/Lib/coroutines-ui/build
88 | - Code/Lib/multi-mvp/build
89 |
90 | deploy-server:
91 | tags:
92 | - nas
93 | only:
94 | - master
95 | stage: deploy
96 | script:
97 | - cd Code
98 | - cp ~/Properties/MultiplatformTemplate/local.properties .
99 | - ./gradlew deployOnlyApp
100 | - cp Server/build/libs/Server-0.0.1.war /var/lib/jetty/webapps/root.war
101 | cache:
102 | key: "${CI_COMMIT_REF_NAME}-App"
103 | policy: pull
104 | paths:
105 | - Code/Server/build
106 | - Code/Shared/build
107 |
108 | environment:
109 | name: staging
110 | url: https://example.chrishatton.org/api/
111 |
112 | # document-client:
113 | # only:
114 | # - master
115 | # stage: buildAndTest
116 | # script:
117 | # - cd Code
118 | # - cp ~/Properties/MultiplatformTemplate/local.properties .
119 | # - cd Client
120 | # - ./gradlew dokka
121 | # - rm -rf /usr/share/nginx/html/example/doc/client/*
122 | # - cp -R build/javadoc/client/* /usr/share/nginx/html/example/doc/client
123 | # - cp build/javadoc/style.css /usr/share/nginx/html/example/doc
124 | # cache:
125 | # key: "$CI_COMMIT_REF_NAME"
126 | # policy: pull
127 | # paths:
128 | # - build
129 | # - .gradle
130 |
131 | # Uses Kotlin's 'Dokka' plugin to generate and deploy documentation for the Server project
132 | # (including the supporting 'Shared' framework)
133 | document-server:
134 | tags:
135 | - nas
136 | only:
137 | - master
138 | stage: buildAndTest
139 | script:
140 | - cd Code
141 | - cp ~/Properties/MultiplatformTemplate/local.properties .
142 | - cd Server
143 | - ./gradlew dokka
144 | - mkdir -p /usr/share/nginx/html/example/doc/server/
145 | - rm -rf /usr/share/nginx/html/example/doc/server/*
146 | - cp -R build/javadoc/server/* /usr/share/nginx/html/example/doc/server/
147 | - cp build/javadoc/style.css /usr/share/nginx/html/example/doc/
148 | cache:
149 | key: "${CI_COMMIT_REF_NAME}-App"
150 | policy: pull
151 | paths:
152 | - build
153 | - .gradle
154 |
--------------------------------------------------------------------------------
/Code/Client/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | local.properties
9 |
10 |
--------------------------------------------------------------------------------
/Code/Client/Android/.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 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /**
2 | * Build file for the 'Android-Client-shared' module of this Kotlin Multi-platform Application.
3 | *
4 | * Source files implemented in this module are accessible to all Android Client projects.
5 | * Currently this means to both the Android Mobile/Tablet module and the Android TV module.
6 | * Typically this module would be used to share common Fragments, custom Views or other parts
7 | * of the View layer (of the MVP architecture) which it is not desirable to re-implement
8 | * for both Android projects.
9 | */
10 |
11 | apply( from = "../../../shared.gradle.kts")
12 |
13 | val androidBuildToolsVersion : String by extra
14 | val androidCompileSdkVersion : String by extra
15 | val androidTargetSdkVersion : String by extra
16 | val androidMinSdkVersion : String by extra
17 |
18 | plugins {
19 | id("com.android.library")
20 | id("org.jetbrains.kotlin.multiplatform") // We should be able to use `kotlin("android")` but Android Studio fails to resolve symbols from composite KMP libraries.
21 | id("kotlin-android-extensions")
22 | id("kotlinx-serialization")
23 | }
24 |
25 | val ccp = configurations.create("compileClasspath")
26 | configurations.add(ccp)
27 |
28 | android {
29 | buildToolsVersion = androidBuildToolsVersion
30 |
31 | compileSdkVersion(androidCompileSdkVersion.toInt())
32 | defaultConfig {
33 | multiDexEnabled = true
34 | minSdkVersion(androidMinSdkVersion.toInt())
35 | targetSdkVersion(androidTargetSdkVersion.toInt())
36 | versionCode = 1
37 | versionName = "1.0"
38 | testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
39 | }
40 | buildTypes {
41 | getByName("debug"){}
42 | getByName("release") {
43 | isMinifyEnabled = false
44 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
45 | }
46 | }
47 | packagingOptions {
48 | exclude("META-INF/ktor-http.kotlin_module")
49 | exclude("META-INF/kotlinx-io.kotlin_module")
50 | exclude("META-INF/atomicfu.kotlin_module")
51 | exclude("META-INF/ktor-utils.kotlin_module")
52 | exclude("META-INF/kotlinx-coroutines-io.kotlin_module")
53 | exclude("META-INF/kotlinx-coroutines-core.kotlin_module")
54 | exclude("META-INF/ktor-client-core.kotlin_module")
55 | exclude("META-INF/ktor-http-cio.kotlin_module")
56 | exclude("META-INF/ktor-io.kotlin_module")
57 | }
58 | sourceSets {
59 | this["main"].java.srcDir("src/androidMain/kotlin")
60 | this["test"].java.srcDir("src/androidTest/kotlin")
61 | this["androidTest"].java.srcDir("src/androidAndroidTest/kotlin")
62 | }
63 | lintOptions {
64 | isCheckReleaseBuilds = false
65 | isAbortOnError = false
66 | }
67 | }
68 |
69 | val multiMvp : String by extra
70 |
71 | val ktorClientAndroid : String by extra
72 | val ktorClientJson : String by extra
73 |
74 | val kotlinXCoroutinesAndroid : String by extra
75 | val androidXAppCompat : String by extra
76 |
77 | val jUnit : String by extra
78 |
79 | val clientSharedProject : ()->ProjectDependency by extra
80 | val sharedProject : ()->ProjectDependency by extra
81 |
82 | val androidXTestRunner : String by extra
83 | val androidXTestEspressoCore : String by extra
84 |
85 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
86 |
87 | kotlin {
88 | android("android") {
89 | attributes.attribute(frameworkAttribute, "android")
90 | publishLibraryVariants("release", "debug") // Required for Android to publish
91 | publishLibraryVariantsGroupedByFlavor = true
92 | }
93 |
94 | sourceSets {
95 | val androidMain by getting {
96 | dependencies {
97 |
98 | implementation(clientSharedProject())
99 | implementation(sharedProject())
100 |
101 | implementation(multiMvp)
102 |
103 | // Android
104 | implementation(kotlinXCoroutinesAndroid)
105 | implementation(androidXAppCompat)
106 |
107 | // Ktor
108 | implementation(ktorClientAndroid)
109 | implementation(ktorClientJson)
110 | }
111 | }
112 |
113 | val androidTest by getting {
114 | dependencies {
115 | // Test
116 | implementation(jUnit)
117 |
118 | // Android Test
119 | implementation(androidXTestRunner)
120 | implementation(androidXTestEspressoCore)
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidAndroidTest/kotlin/org/chrishatton/example/common/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.common;
2 |
3 | import android.content.Context;
4 | import androidx.test.InstrumentationRegistry;
5 | import androidx.test.runner.AndroidJUnit4;
6 | import org.junit.Test;
7 | import org.junit.runner.RunWith;
8 |
9 | import static org.junit.Assert.assertEquals;
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * @see Testing documentation
15 | */
16 | @RunWith(AndroidJUnit4.class)
17 | public class ExampleInstrumentedTest {
18 | @Test
19 | public void useAppContext() {
20 | // Context of the app under test.
21 | Context appContext = InstrumentationRegistry.getTargetContext();
22 |
23 | assertEquals("org.chrishatton.example", appContext.getPackageName());
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidMain/kotlin/org/chrishatton/example/common/FirstFragment.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.common
2 |
3 | import android.os.Bundle
4 | import android.view.LayoutInflater
5 | import android.view.View
6 | import android.view.ViewGroup
7 | import kotlinx.android.synthetic.main.fragment_first.*
8 | import kotlinx.android.synthetic.main.fragment_first.view.*
9 | import kotlinx.coroutines.InternalCoroutinesApi
10 | import org.chrishatton.example.ui.FirstContract
11 | import org.chrishatton.example.ui.FirstPresenter
12 | import org.chrishatton.multimvp.ui.BaseViewFragment
13 |
14 | @InternalCoroutinesApi
15 | @kotlinx.coroutines.ExperimentalCoroutinesApi
16 | class FirstFragment : BaseViewFragment(),
17 | FirstContract.View {
18 |
19 | override fun displayGreeting(text: String) {
20 | responseText.text = text
21 | }
22 |
23 | override val presenter : FirstPresenter by lazy {
24 | FirstPresenter(
25 | baseUrl = "http://10.0.2.2:8080",
26 | view = this
27 | )
28 | }
29 |
30 | override fun onCreateView(
31 | inflater: LayoutInflater, container: ViewGroup?,
32 | savedInstanceState: Bundle?
33 | ): View? {
34 | // Inflate the layout for this fragment
35 | return inflater.inflate(R.layout.fragment_first, container, false).also { view ->
36 | view.sendButton.setOnClickListener {
37 | presenter.didSetName(nameEntry.text.toString())
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidMain/kotlin/org/chrishatton/example/common/package.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.common
2 |
3 | /*
4 | This package is for Android code common across the 'mobile' and 'TV' targets.
5 | It is expected that many Fragments and Activities will be viable across both targets,
6 | although some will benefit from UI/UX specialisation toward each differing format.
7 | */
8 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidMain/res/layout/fragment_first.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
9 |
10 |
16 |
17 |
26 |
27 |
33 |
34 |
40 |
41 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidMain/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | bm_client_android_common
3 | Hello blank fragment
4 |
5 | Enter your name
6 | Server will respond here
7 | Your name
8 |
9 |
--------------------------------------------------------------------------------
/Code/Client/Android/android-client-shared/src/androidTest/kotlin/org/chrishatton/example/common/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.common
2 |
3 | import org.junit.Assert.assertEquals
4 | import org.junit.Test
5 |
6 | /**
7 | * Example local unit test, which will execute on the development machine (host).
8 | *
9 | * @see [Testing documentation](http://d.android.com/tools/testing)
10 | */
11 | class ExampleUnitTest {
12 | @Test
13 | fun addition_isCorrect() {
14 | assertEquals(4, 2 + 2)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Code/Client/Android/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | apply( from = "../../shared.gradle.kts")
3 |
4 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
5 |
6 | buildscript {
7 |
8 | apply( from = "../../shared.gradle.kts")
9 |
10 | val kotlinVersion : String by extra
11 | val androidGradlePlugin : String by extra
12 | val androidGradleDokkaPlugin : String by extra
13 |
14 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
15 | repositories(configureSharedRepositories)
16 |
17 | dependencies {
18 | classpath(androidGradlePlugin)
19 | classpath(kotlin("gradle-plugin", version = kotlinVersion))
20 | classpath(androidGradleDokkaPlugin)
21 | classpath("org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion")
22 | }
23 | }
24 |
25 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
26 | repositories(configureSharedRepositories)
27 |
28 | allprojects {
29 | repositories(configureSharedRepositories)
30 | }
31 |
--------------------------------------------------------------------------------
/Code/Client/Android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
--------------------------------------------------------------------------------
/Code/Client/Android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/Client/Android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat May 04 22:14:32 AEST 2019
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.4.1-bin.zip
7 |
--------------------------------------------------------------------------------
/Code/Client/Android/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 |
--------------------------------------------------------------------------------
/Code/Client/Android/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 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | *
4 | * Build file for the 'Android Mobile/Tablet' module of this Kotlin Multi-platform Application.
5 | *
6 | */
7 |
8 | apply( from = "../../../shared.gradle.kts")
9 |
10 | plugins {
11 | id("com.android.application")
12 | id("org.jetbrains.kotlin.multiplatform") // We should be able to use `kotlin("android")` but Android Studio fails to resolve symbols from composite KMP libraries.
13 | id("kotlin-android-extensions")
14 | id("kotlinx-serialization")
15 | }
16 |
17 | val ktorClientAndroid : String by extra
18 | val ktorClientJson : String by extra
19 | val androidXAppCompat : String by extra
20 | val androidXCoreKtx : String by extra
21 | val androidXConstraintLayout : String by extra
22 | val kotlinXCoroutinesAndroid : String by extra
23 | val jUnit : String by extra
24 | val androidXTestRunner : String by extra
25 | val androidXTestEspressoCore : String by extra
26 |
27 | val androidBuildToolsVersion : String by extra
28 | val androidCompileSdkVersion : String by extra
29 | val androidTargetSdkVersion : String by extra
30 | val androidMinSdkVersion : String by extra
31 |
32 | val androidclientSharedProject : ()->ProjectDependency by extra
33 | val clientSharedProject : ()->ProjectDependency by extra
34 | val sharedProject : ()->ProjectDependency by extra
35 |
36 | val multiMvp : String by extra
37 |
38 | android {
39 | buildToolsVersion = androidBuildToolsVersion
40 |
41 | compileSdkVersion(androidCompileSdkVersion.toInt())
42 | defaultConfig {
43 | multiDexEnabled = true
44 | applicationId = "org.chrishatton.example"
45 | minSdkVersion(androidMinSdkVersion.toInt())
46 | targetSdkVersion(androidTargetSdkVersion.toInt())
47 | versionCode = 1
48 | versionName = "1.0"
49 | testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
50 | }
51 | buildTypes {
52 | getByName("debug"){}
53 | getByName("release") {
54 | isMinifyEnabled = false
55 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
56 | }
57 | }
58 | packagingOptions {
59 | exclude("META-INF/ktor-http.kotlin_module")
60 | exclude("META-INF/kotlinx-io.kotlin_module")
61 | exclude("META-INF/atomicfu.kotlin_module")
62 | exclude("META-INF/ktor-utils.kotlin_module")
63 | exclude("META-INF/kotlinx-coroutines-io.kotlin_module")
64 | exclude("META-INF/kotlinx-coroutines-core.kotlin_module")
65 | exclude("META-INF/ktor-client-core.kotlin_module")
66 | exclude("META-INF/ktor-http-cio.kotlin_module")
67 | exclude("META-INF/ktor-client-json.kotlin_module")
68 | exclude("META-INF/kotlinx-serialization-runtime.kotlin_module")
69 | exclude("META-INF/multi-mvp_release.kotlin_module")
70 | exclude("META-INF/ktor-io.kotlin_module")
71 | }
72 | sourceSets {
73 | this["main"].java.srcDir("src/androidMain/kotlin")
74 | this["test"].java.srcDir("src/androidTest/kotlin")
75 | this["androidTest"].java.srcDir("src/androidAndroidTest/kotlin")
76 | }
77 | }
78 |
79 | @Suppress("UNCHECKED_CAST")
80 |
81 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
82 |
83 | kotlin {
84 | android("android") {
85 | attributes.attribute(frameworkAttribute, "android")
86 | //publishLibraryVariants("release", "debug") // Required for Android to publish
87 | publishLibraryVariantsGroupedByFlavor = true
88 | }
89 |
90 | sourceSets {
91 | val androidMain by getting {
92 | dependencies {
93 |
94 | // Projects
95 | implementation(androidclientSharedProject())
96 | implementation(clientSharedProject())
97 | implementation(sharedProject())
98 |
99 | implementation(multiMvp)
100 |
101 | // Ktor
102 | implementation(ktorClientAndroid)
103 | implementation(ktorClientJson)
104 |
105 | // Android
106 | implementation(androidXAppCompat)
107 | implementation(androidXCoreKtx)
108 | implementation(androidXConstraintLayout)
109 | implementation(kotlinXCoroutinesAndroid)
110 | }
111 | }
112 |
113 | val androidTest by getting {
114 | dependencies {
115 | // Test
116 | implementation(jUnit)
117 |
118 | // Android Test
119 | implementation(androidXTestRunner)
120 | implementation(androidXTestEspressoCore)
121 | }
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidAndroidTest/kotlin/example/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import androidx.test.InstrumentationRegistry
4 | import androidx.test.runner.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getTargetContext()
22 | assertEquals("org.chrishatton.project", appContext.packageName)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/kotlin/org/chrishatton/example/mobile/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.mobile
2 |
3 | import android.os.Bundle
4 | import androidx.fragment.app.FragmentActivity
5 |
6 | class MainActivity : FragmentActivity() {
7 |
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | setContentView(R.layout.activity_main)
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
12 |
13 |
19 |
22 |
25 |
26 |
27 |
28 |
34 |
35 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
22 |
24 |
26 |
28 |
30 |
32 |
34 |
36 |
38 |
40 |
42 |
44 |
46 |
48 |
50 |
52 |
54 |
56 |
58 |
60 |
62 |
64 |
66 |
68 |
70 |
72 |
74 |
75 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-hdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-mdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/mobile/src/androidMain/res/mipmap-xxxhdpi/ic_launcher_round.png
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #008577
4 | #00574B
5 | #D81B60
6 |
7 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Example
3 |
4 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidMain/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Code/Client/Android/mobile/src/androidTest/kotlin/example/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Code/Client/Android/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.io.File
2 |
3 | apply( from = "../client-shared.settings.gradle.kts" )
4 |
5 | rootProject.name = "client-android"
6 |
7 | include(":mobile",":tv",":android-client-shared")
8 |
9 | // The Android library shared between Android clients
10 | project(":android-client-shared").projectDir = File(settingsDir, "./android-client-shared")
11 |
12 | gradle.startParameter.setExcludedTaskNames(listOf("lint","lintVitalRelease"))
--------------------------------------------------------------------------------
/Code/Client/Android/tv/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * Build file for the 'Android TV' module of this Kotlin Multi-platform Application.
4 | *
5 | */
6 |
7 | apply( from = "../../../shared.gradle.kts")
8 |
9 | plugins {
10 | id("com.android.application")
11 | id("org.jetbrains.kotlin.multiplatform") // We should be able to use `kotlin("android")` but Android Studio fails to resolve symbols from composite KMP libraries.
12 | id("kotlin-android-extensions")
13 | id("kotlinx-serialization")
14 | }
15 |
16 | val ktorClientAndroid : String by extra
17 | val ktorClientJson : String by extra
18 | val androidXAppCompat : String by extra
19 | val androidXCoreKtx : String by extra
20 | val androidXConstraintLayout : String by extra
21 | val kotlinXCoroutinesAndroid : String by extra
22 | val jUnit : String by extra
23 | val androidXTestRunner : String by extra
24 | val androidXTestEspressoCore : String by extra
25 |
26 | val androidBuildToolsVersion : String by extra
27 | val androidCompileSdkVersion : String by extra
28 | val androidTargetSdkVersion : String by extra
29 | val androidMinSdkVersion : String by extra
30 |
31 | val androidTvLeanback : String by extra
32 | val glideImageLibrary : String by extra
33 |
34 | val androidclientSharedProject : ()->ProjectDependency by extra
35 | val clientSharedProject : ()->ProjectDependency by extra
36 | val sharedProject : ()->ProjectDependency by extra
37 |
38 | android {
39 |
40 | buildToolsVersion = androidBuildToolsVersion
41 |
42 | compileSdkVersion(androidCompileSdkVersion.toInt())
43 |
44 | defaultConfig {
45 | multiDexEnabled = true
46 | applicationId = "org.chrishatton.example"
47 | minSdkVersion(androidMinSdkVersion.toInt())
48 | targetSdkVersion(androidTargetSdkVersion.toInt())
49 | versionCode = 1
50 | versionName = "1.0"
51 | testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner"
52 | }
53 |
54 | buildTypes {
55 | getByName("debug"){}
56 | getByName("release") {
57 | isMinifyEnabled = false
58 | proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
59 | }
60 | }
61 |
62 | packagingOptions {
63 | exclude("META-INF/ktor-http.kotlin_module")
64 | exclude("META-INF/kotlinx-io.kotlin_module")
65 | exclude("META-INF/atomicfu.kotlin_module")
66 | exclude("META-INF/ktor-utils.kotlin_module")
67 | exclude("META-INF/kotlinx-coroutines-io.kotlin_module")
68 | exclude("META-INF/kotlinx-coroutines-core.kotlin_module")
69 | exclude("META-INF/ktor-client-core.kotlin_module")
70 | exclude("META-INF/ktor-http-cio.kotlin_module")
71 | exclude("META-INF/ktor-client-json.kotlin_module")
72 | exclude("META-INF/kotlinx-serialization-runtime.kotlin_module")
73 | exclude("META-INF/ktor-io.kotlin_module")
74 | }
75 |
76 | sourceSets {
77 | this["main"].java.srcDir("src/androidMain/kotlin")
78 | this["test"].java.srcDir("src/androidTest/kotlin")
79 | this["androidTest"].java.srcDir("src/androidAndroidTest/kotlin")
80 | }
81 | }
82 |
83 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
84 |
85 | kotlin {
86 | android("android") {
87 | attributes.attribute(frameworkAttribute, "android")
88 | //publishLibraryVariants("release", "debug") // Required for Android to publish
89 | publishLibraryVariantsGroupedByFlavor = true
90 | }
91 |
92 | sourceSets {
93 | val androidMain by getting {
94 | dependencies {
95 |
96 | // Projects
97 | implementation(androidclientSharedProject())
98 | implementation(clientSharedProject())
99 | implementation(sharedProject())
100 |
101 | // Ktor
102 | implementation(ktorClientAndroid)
103 | implementation(ktorClientJson)
104 |
105 | // Android
106 | implementation(androidXAppCompat)
107 | implementation(androidXCoreKtx)
108 | implementation(androidXConstraintLayout)
109 | implementation(kotlinXCoroutinesAndroid)
110 |
111 | // Android TV
112 | implementation(androidTvLeanback)
113 | implementation(glideImageLibrary)
114 | }
115 | }
116 |
117 | val androidTest by getting {
118 | dependencies {
119 | // Test
120 | implementation(jUnit)
121 |
122 | // Android Test
123 | implementation(androidXTestRunner)
124 | implementation(androidXTestEspressoCore)
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.kts.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
22 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
12 |
13 |
19 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/kotlin/org/chrishatton/example/tv/MainActivity.kt:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017 The Android Open Source Project
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
5 | * in compliance with the License. You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software distributed under the License
10 | * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
11 | * or implied. See the License for the specific language governing permissions and limitations under
12 | * the License.
13 | */
14 |
15 | package org.chrishatton.example.tv
16 |
17 | import android.os.Bundle
18 | import androidx.fragment.app.FragmentActivity
19 |
20 | /**
21 | * Loads [MainFragment].
22 | */
23 | class MainActivity : FragmentActivity() {
24 |
25 | override fun onCreate(savedInstanceState: Bundle?) {
26 | super.onCreate(savedInstanceState)
27 | setContentView(R.layout.activity_main)
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/drawable/app_icon_your_company.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/drawable/app_icon_your_company.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/drawable/default_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
9 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/drawable/movie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/drawable/movie.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/layout/activity_details.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Android/tv/src/androidMain/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 | #000000
3 | #DDDDDD
4 | #0096a6
5 | #ffaa3f
6 | #ffaa3f
7 | #3d3d3d
8 |
9 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Example
3 |
4 | Related Videos
5 | Grid View
6 | Error Fragment
7 | Personal Settings
8 | Watch trailer
9 | FREE
10 | Rent By Day
11 | From $1.99
12 | Buy and Own
13 | AT $9.99
14 | Movie
15 |
16 |
17 | An error occurred
18 | Dismiss
19 |
20 |
--------------------------------------------------------------------------------
/Code/Client/Android/tv/src/androidMain/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Code/Client/Browser/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
3 |
4 |
5 | buildscript {
6 |
7 | apply( from = "../../shared.gradle.kts")
8 |
9 | val kotlinVersion : String by extra
10 | val kotlinSerializationPlugin : String by extra
11 | val androidGradlePlugin : String by extra
12 |
13 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
14 | repositories(configureSharedRepositories)
15 |
16 | dependencies {
17 | classpath(kotlin("gradle-plugin", version = kotlinVersion))
18 | classpath(kotlinSerializationPlugin)
19 | classpath(androidGradlePlugin)
20 | }
21 | }
22 |
23 |
24 | val kotlinVersion : String by extra
25 | val kotlinCoroutinesVersion : String by extra
26 | val ktorVersion : String by extra
27 |
28 | val coroutinesUi : String by extra
29 | val multiMvp : String by extra
30 |
31 | val kotlinXCoroutinesCore : String by extra
32 | val kotlinXCoroutinesCoreJs : String by extra
33 |
34 | val ktorClient : String by extra
35 | val ktorClientJson : String by extra
36 |
37 | val ktorClientJs : String by extra
38 | val ktorClientJsonJs : String by extra
39 | val ktorClientSerializationJs : String by extra
40 |
41 | val kotlinXSerializationRuntimeJs : String by extra
42 |
43 | val jUnit : String by extra
44 |
45 | val kotlinxHtmlJs : String by extra
46 |
47 | //val multiMvpProject : ()->ProjectDependency by extra
48 | val clientSharedProject : ()->ProjectDependency by extra
49 | val sharedProject : ()->ProjectDependency by extra
50 |
51 | repositories {
52 | google()
53 | jcenter()
54 | maven( url = "https://kotlin.bintray.com/kotlinx" )
55 | maven( url = "https://kotlin.bintray.com/kotlin/ktor" )
56 | maven( url = "https://oss.sonatype.org/content/repositories/snapshots/" )
57 | maven( url = "https://oss.jfrog.org/oss-snapshot-local" ) { content { includeGroup("org.chrishatton") } }
58 | maven( url = "https://dl.bintray.com/chris-hatton/lib" ) { content { includeGroup("org.chrishatton") } }
59 | }
60 |
61 | plugins {
62 |
63 | kotlin("js") version "1.4.10"
64 | //id("com.android.library") apply false
65 |
66 | //id("org.jetbrains.kotlin.multiplatform")
67 | id("kotlinx-serialization")
68 | }
69 |
70 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
71 |
72 | kotlin {
73 | js {
74 | browser {
75 | testTask {
76 | useKarma {
77 | useChromeHeadless()
78 | }
79 | }
80 | }
81 | binaries.executable()
82 | attributes.attribute(frameworkAttribute, "js")
83 | }
84 |
85 | sourceSets {
86 |
87 | val main by getting {
88 | dependencies {
89 |
90 | implementation(kotlinxHtmlJs)
91 |
92 | // TODO: Expected setting the attribute to work, but causes issues.
93 | implementation(project(path = ":client-shared")) //{ attributes { attribute(frameworkAttribute, "js") } }
94 | implementation(project(path = ":shared")) //{ attributes { attribute(frameworkAttribute, "js") } }
95 |
96 | implementation(coroutinesUi)
97 | implementation(multiMvp)
98 |
99 | // Kotlin Core
100 | implementation(kotlinXCoroutinesCore)
101 | implementation(kotlinXSerializationRuntimeJs)
102 |
103 | // Ktor
104 | implementation(ktorClientJs)
105 | implementation(ktorClientJsonJs)
106 | implementation(ktorClientSerializationJs)
107 | }
108 | }
109 | val test by getting {
110 | dependencies {
111 | implementation(kotlin("test-js"))
112 | }
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/Code/Client/Browser/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
17 |
--------------------------------------------------------------------------------
/Code/Client/Browser/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Browser/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/Client/Browser/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/Code/Client/Browser/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/Code/Client/Browser/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto init
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto init
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :init
68 | @rem Get command-line arguments, handling Windows variants
69 |
70 | if not "%OS%" == "Windows_NT" goto win9xME_args
71 |
72 | :win9xME_args
73 | @rem Slurp the command line arguments.
74 | set CMD_LINE_ARGS=
75 | set _SKIP=2
76 |
77 | :win9xME_args_slurp
78 | if "x%~1" == "x" goto execute
79 |
80 | set CMD_LINE_ARGS=%*
81 |
82 | :execute
83 | @rem Setup the command line
84 |
85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
86 |
87 |
88 | @rem Execute Gradle
89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
90 |
91 | :end
92 | @rem End local scope for the variables with windows NT shell
93 | if "%ERRORLEVEL%"=="0" goto mainEnd
94 |
95 | :fail
96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
97 | rem the _cmd.exe /c_ return code!
98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
99 | exit /b 1
100 |
101 | :mainEnd
102 | if "%OS%"=="Windows_NT" endlocal
103 |
104 | :omega
105 |
--------------------------------------------------------------------------------
/Code/Client/Browser/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /**
2 | * This Gradle Settings file is needed when opening the Desktop Client project in an IDE.
3 | */
4 |
5 | import java.io.File
6 |
7 | // Apply the settings which are shared across all Client platform projects.
8 | apply( from = "../client-shared.settings.gradle.kts" )
9 |
10 | rootProject.name = "client-browser"
11 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Desktop/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/Client/Desktop/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/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 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/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 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | /**
2 | * This Gradle Settings file is needed when opening the Desktop Client project in an IDE.
3 | */
4 |
5 | // Apply the settings which are shared across all Client platform projects.
6 | apply( from = "../client-shared.settings.gradle.kts" )
7 |
8 | rootProject.name = "client"
9 |
10 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/javafxMain/kotlin/org/chrishatton/example/ExampleApp.kt:
--------------------------------------------------------------------------------
1 |
2 | package org.chrishatton.example
3 |
4 | import javafx.application.Application
5 | import javafx.scene.Scene
6 | import javafx.stage.Stage
7 | import kotlinx.coroutines.*
8 | import org.chrishatton.multimvp.ui.BaseFxmlView
9 | import org.chrishatton.multimvp.ui.Cycleable
10 | import org.chrishatton.multimvp.ui.CycleableMixIn
11 | import org.chrishatton.multimvp.util.processDispatcher
12 |
13 | @FlowPreview
14 | @ExperimentalCoroutinesApi
15 | @InternalCoroutinesApi
16 | class ExampleApp : Application(), Cycleable by CycleableMixIn( scopeCreator = {
17 | CoroutineScope( processDispatcher + SupervisorJob() )
18 | } ) {
19 |
20 | private lateinit var view : BaseFxmlView<*,*>
21 |
22 | override fun start(primaryStage: Stage) {
23 | primaryStage.title = "Hello World!"
24 |
25 | view = NoteListView()
26 |
27 | primaryStage.scene = Scene(view.root, 640.0, 480.0)
28 | primaryStage.show()
29 |
30 | view.start()
31 | }
32 |
33 | override fun stop() {
34 | view.stop()
35 | super.stop()
36 | }
37 | }
38 |
39 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/javafxMain/kotlin/org/chrishatton/example/NoteListView.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import javafx.scene.control.Button
4 | import javafx.scene.control.Label
5 | import javafx.scene.control.TextField
6 | import kotlinx.coroutines.*
7 |
8 | import org.chrishatton.example.ui.FirstPresenter
9 | import org.chrishatton.multimvp.util.fxml
10 | import org.chrishatton.multimvp.ui.BaseFxView
11 | import org.chrishatton.multimvp.ui.BaseFxmlView
12 | import org.chrishatton.multimvp.util.fxid
13 | import org.chrishatton.example.ui.FirstContract.View as View
14 | import org.chrishatton.example.ui.FirstContract.Presenter as Presenter
15 |
16 | @FlowPreview
17 | @ExperimentalCoroutinesApi
18 | @InternalCoroutinesApi
19 | class NoteListView : BaseFxmlView(), View {
20 |
21 | val submitButton : Button by fxid()
22 | val nameField : TextField by fxid()
23 | val replyLabel : Label by fxid()
24 |
25 | override fun displayGreeting(text: String) {
26 | lifecycleScope!!.launch {
27 | replyLabel.text = text
28 | }
29 | }
30 |
31 | override val presenter: Presenter by lazy {
32 | FirstPresenter(baseUrl = "http://localhost:8080", view = this)
33 | }
34 |
35 | override fun startLifecycle() {
36 | submitButton.setOnAction {
37 | val name = nameField.text
38 | lifecycleScope!!.launch {
39 | presenter.didSetName(name)
40 | }
41 | }
42 | }
43 |
44 | override fun stopLifecycle() {
45 | submitButton.setOnAction {}
46 | }
47 | }
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/javafxMain/resources/org/chrishatton/example/NewNoteView.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/javafxMain/resources/org/chrishatton/example/NoteListCell.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/javafxMain/resources/org/chrishatton/example/NoteListView.fxml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/Code/Client/Desktop/src/test/kotlin/sample/SampleTestsJavafx.kt:
--------------------------------------------------------------------------------
1 | package sample
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class SampleTestsJavafx {
7 | @Test
8 | fun testHello() {
9 | //assertTrue("JavaFX" in hello())
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Code/Client/Shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | /**
2 | *1.
3 | * Build file for the 'Client-shared' module of this Kotlin Multi-platform Application.
4 | *
5 | * Source files implemented in this module are accessible to all Client projects.
6 | * UI Presentation logic and other Client-side business logic should reside in this module.
7 | * The Presenters of the MVP architecture should be implemented in this module.
8 | *
9 | */
10 |
11 | buildscript {
12 | apply( from = "../../shared.gradle.kts")
13 | //val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
14 | //repositories(configureSharedRepositories)
15 | }
16 |
17 | val isMinJava12 : Boolean = JavaVersion.current() >= JavaVersion.VERSION_12
18 |
19 | val kotlinXCoroutinesCore : String by extra
20 |
21 | val multiMvp : String by extra
22 | val coroutinesUi : String by extra
23 |
24 | val kotlinXSerializationRuntime : String by extra
25 |
26 | val ktorClient : String by extra
27 | val ktorClientAndroid : String by extra
28 | val ktorClientIos : String by extra
29 | val ktorClientCore : String by extra
30 | val ktorClientCoreJvm : String by extra
31 | val ktorClientCoreNative : String by extra
32 | val ktorClientJson : String by extra
33 | val ktorClientSerialization : String by extra
34 | val ktorClientAuth : String by extra
35 |
36 | val sharedProject : ()->ProjectDependency by extra
37 |
38 | val isIosDevice : Boolean by extra
39 |
40 | plugins {
41 | id("com.android.library")
42 | id("org.jetbrains.kotlin.multiplatform")
43 | kotlin("plugin.serialization")
44 | }
45 |
46 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
47 | repositories(configureSharedRepositories)
48 |
49 | android {
50 | compileSdkVersion(29)
51 | defaultConfig {
52 | minSdkVersion(21)
53 | targetSdkVersion(29)
54 | versionCode = 1
55 | versionName = "1.0"
56 | }
57 | buildTypes {
58 | getByName("release") {
59 | isMinifyEnabled = false
60 | }
61 | }
62 | sourceSets {
63 | val main by getting {
64 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
65 | java.srcDirs("src/androidMain/kotlin")
66 | res.srcDirs("src/androidMain/res")
67 | }
68 | val test by getting {
69 | java.srcDirs("src/androidTest/kotlin")
70 | res.srcDirs("src/androidTest/res")
71 | }
72 | }
73 | }
74 |
75 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
76 |
77 | kotlin {
78 |
79 | android("android") {
80 | attributes.attribute(frameworkAttribute, "android")
81 | }
82 |
83 | if(isMinJava12) {
84 | jvm("javafx") { attributes.attribute(frameworkAttribute, "javafx") }
85 | }
86 |
87 | val iosTarget = if(isIosDevice) iosArm64("ios") else iosX64("ios")
88 | iosTarget.apply {
89 | binaries {
90 | framework {
91 | if (!isIosDevice) {
92 | embedBitcode("disable")
93 | }
94 | }
95 | }
96 | attributes.attribute(frameworkAttribute, "ios")
97 | }
98 |
99 | js("browser",IR) {
100 | browser {
101 | }
102 | binaries.executable()
103 | attributes.attribute(frameworkAttribute, "js")
104 | }
105 |
106 | sourceSets {
107 |
108 | commonMain {
109 | dependencies {
110 | implementation(multiMvp)
111 | implementation(coroutinesUi)
112 |
113 | implementation(project(path = ":shared"))
114 |
115 | implementation(ktorClientCore)
116 | implementation(kotlinXCoroutinesCore)
117 | implementation(ktorClientJson)
118 | implementation(ktorClientSerialization)
119 | implementation(ktorClientAuth)
120 | }
121 | }
122 | commonTest {
123 | dependencies {
124 | implementation(kotlin("test-common"))
125 | implementation(kotlin("test-annotations-common"))
126 | }
127 | }
128 |
129 | val iosMain by getting {
130 | dependencies {
131 | implementation(multiMvp)
132 | implementation(coroutinesUi)
133 |
134 | implementation(kotlinXCoroutinesCore)
135 |
136 | implementation(kotlinXSerializationRuntime)
137 | implementation(ktorClientIos)
138 | implementation(ktorClientJson)
139 | implementation(ktorClientSerialization)
140 | }
141 | }
142 | val iosTest by getting {
143 | }
144 |
145 | val androidMain by getting {
146 | dependencies {
147 | implementation(kotlinXCoroutinesCore)
148 | implementation(kotlinXSerializationRuntime)
149 |
150 | implementation(multiMvp)
151 | implementation(coroutinesUi)
152 |
153 | implementation(ktorClientCore)
154 | implementation(ktorClientJson)
155 | implementation(ktorClientSerialization)
156 | }
157 | }
158 |
159 | val androidTest by getting {
160 | dependencies {
161 |
162 | implementation(kotlin("test-junit"))
163 | //implementation(kotlin("test-annotations"))
164 | }
165 | }
166 |
167 | if(isMinJava12) {
168 | val javafxMain by getting {
169 |
170 | dependencies {
171 | implementation(multiMvp)
172 | implementation(coroutinesUi)
173 |
174 | implementation(kotlinXCoroutinesCore)
175 | implementation(kotlinXSerializationRuntime)
176 |
177 | implementation(ktorClientCore)
178 | implementation(ktorClientJson)
179 | implementation(ktorClientSerialization)
180 | }
181 | }
182 | val javafxTest by getting {
183 | dependencies {
184 | implementation(kotlin("test-junit"))
185 | }
186 | }
187 | }
188 |
189 | val browserMain by getting {
190 | dependencies {
191 | implementation(multiMvp)
192 | implementation(coroutinesUi)
193 | }
194 | }
195 |
196 | val browserTest by getting {
197 | dependencies {
198 |
199 | }
200 | }
201 | }
202 | }
203 |
204 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/androidMain/kotlin/org/chrishatton/example/ExampleClient.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import org.chrishatton.example.model.Person
4 | import io.ktor.client.HttpClient
5 | import io.ktor.client.features.json.JsonFeature
6 | import io.ktor.client.features.json.serializer.KotlinxSerializer
7 |
8 | actual val client : HttpClient = HttpClient {
9 | install(JsonFeature) {
10 | serializer = KotlinxSerializer().apply {
11 | //setMapper( type = Person::class, serializer = Person.serializer())
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/androidMain/kotlin/org/chrishatton/example/Platform.kt:
--------------------------------------------------------------------------------
1 |
2 | package org.chrishatton.example
3 |
4 | actual val platformName : String = "JVM"
5 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/androidTest/kotlin/org/chrishatton/example/package.kt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Shared/src/androidTest/kotlin/org/chrishatton/example/package.kt
--------------------------------------------------------------------------------
/Code/Client/Shared/src/commonMain/kotlin/org/chrishatton/example/ExampleClient.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import io.ktor.client.HttpClient
4 |
5 | expect val client : HttpClient
--------------------------------------------------------------------------------
/Code/Client/Shared/src/commonMain/kotlin/org/chrishatton/example/Platform.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | expect val platformName : String
4 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/commonMain/kotlin/org/chrishatton/example/ui/FirstContract.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.ui
2 |
3 | import org.chrishatton.multimvp.ui.Contract
4 |
5 | interface FirstContract : Contract {
6 | interface Presenter : Contract.Presenter, FirstContract {
7 | fun didSetName(name: String)
8 | }
9 |
10 | interface View : Contract.View, FirstContract {
11 | fun displayGreeting(text: String)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/commonMain/kotlin/org/chrishatton/example/ui/FirstPresenter.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.ui
2 |
3 | import io.ktor.client.request.post
4 | import io.ktor.http.ContentType
5 | import io.ktor.http.contentType
6 | import io.ktor.http.takeFrom
7 | import kotlinx.coroutines.FlowPreview
8 | import kotlinx.coroutines.channels.Channel
9 | import kotlinx.coroutines.launch
10 | import kotlinx.coroutines.withContext
11 | import org.chrishatton.example.client
12 | import org.chrishatton.example.model.Person
13 | import org.chrishatton.multimvp.ui.BasePresenter
14 | import org.chrishatton.multimvp.util.ioDispatcher
15 | import org.chrishatton.example.ui.FirstContract.View as View
16 | import org.chrishatton.example.ui.FirstContract.Presenter as Presenter
17 |
18 | @FlowPreview
19 | @kotlinx.coroutines.InternalCoroutinesApi
20 | @kotlinx.coroutines.ExperimentalCoroutinesApi
21 | class FirstPresenter(
22 | val baseUrl : String,
23 | view: View
24 | ) : BasePresenter(view), Presenter {
25 | private lateinit var setNameChannel : Channel
26 | private lateinit var peopleChannel : Channel>
27 |
28 | override fun start() {
29 | super.start()
30 | require(lifecycleScope!=null)
31 |
32 | setNameChannel = Channel()
33 | peopleChannel = Channel()
34 |
35 | lifecycleScope.launch {
36 | for (name in setNameChannel) {
37 | val person = Person(names = name.split(" "))
38 | val otherPerson = try {
39 | println("A")
40 | val returnPerson = withContext(ioDispatcher) {
41 | client.post {
42 |
43 | url {
44 | takeFrom("$baseUrl/person")
45 | }
46 | contentType(ContentType.Application.Json)
47 | body = person
48 | }
49 | }
50 | println("B")
51 | returnPerson
52 | } catch(e: Exception) {
53 | println("Exception: $e, cause: ${e.cause}")
54 | Person("Nigel", "Ernest", "Body")
55 | }
56 | peopleChannel.send(person to otherPerson)
57 | }
58 | }
59 |
60 | lifecycleScope.launch {
61 | for((person,otherPerson) in peopleChannel) {
62 | view.displayGreeting(text = "Hello ${person.firstName}, do you know ${otherPerson.fullName}?")
63 | }
64 | }
65 | }
66 |
67 | override fun stop() {
68 | super.stop()
69 | setNameChannel.close()
70 | peopleChannel.close()
71 | }
72 |
73 | override fun didSetName(name: String) {
74 | setNameChannel.offer(name)
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/commonTest/kotlin/org/chrishatton/example/CommonPlatformTests.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import org.chrishatton.example.platformName
4 | import kotlin.test.Test
5 | import kotlin.test.assertTrue
6 |
7 | class CommonPlatformTests {
8 | @Test
9 | fun testPlatform() {
10 | assertTrue(platformName.isNotBlank())
11 | }
12 | }
--------------------------------------------------------------------------------
/Code/Client/Shared/src/iosMain/kotlin/org/chrishatton/example/ExampleClient.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import org.chrishatton.example.model.Person
4 | import io.ktor.client.HttpClient
5 | import io.ktor.client.features.json.JsonFeature
6 | import io.ktor.client.features.json.serializer.KotlinxSerializer
7 |
8 | actual val client : HttpClient by lazy {
9 | HttpClient {
10 | install(JsonFeature) {
11 | serializer = KotlinxSerializer().apply {
12 | //setMapper( type = Person::class, serializer = Person.serializer())
13 | }
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/iosMain/kotlin/org/chrishatton/example/Platform.kt:
--------------------------------------------------------------------------------
1 |
2 | package org.chrishatton.example
3 |
4 | actual val platformName : String = "iOS"
5 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/javafxMain/kotlin/org/chrishatton/example/ExampleClient.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import org.chrishatton.example.model.Person
4 | import io.ktor.client.HttpClient
5 | import io.ktor.client.features.json.JsonFeature
6 | import io.ktor.client.features.json.serializer.KotlinxSerializer
7 |
8 | actual val client : HttpClient = HttpClient {
9 | install(JsonFeature) {
10 | serializer = KotlinxSerializer().apply {
11 | //setMapper( type = Person::class, serializer = Person.serializer())
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/javafxMain/kotlin/org/chrishatton/example/Platform.kt:
--------------------------------------------------------------------------------
1 |
2 | package org.chrishatton.example
3 |
4 | actual val platformName : String = "JVM"
5 |
--------------------------------------------------------------------------------
/Code/Client/Shared/src/javafxTest/kotlin/org/chrishatton/example/package.kt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/Shared/src/javafxTest/kotlin/org/chrishatton/example/package.kt
--------------------------------------------------------------------------------
/Code/Client/build.gradle.kts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/build.gradle.kts
--------------------------------------------------------------------------------
/Code/Client/client-shared.build.gradle.kts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/client-shared.build.gradle.kts
--------------------------------------------------------------------------------
/Code/Client/client-shared.settings.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | apply( from = "../shared.settings.gradle.kts" )
3 |
4 | include(":client-shared")
5 | project(":client-shared").projectDir = File(buildscript.sourceFile!!.parent,"Shared")
6 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example.xcodeproj/project.xcworkspace/xcuserdata/Chris.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example.xcodeproj/xcshareddata/xcschemes/Example.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
34 |
35 |
45 |
47 |
53 |
54 |
55 |
56 |
57 |
60 |
61 |
62 |
68 |
69 |
71 |
72 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/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 | "info" : {
90 | "version" : 1,
91 | "author" : "xcode"
92 | }
93 | }
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/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 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/Base.lproj/Main.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 |
27 |
28 |
29 |
38 |
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 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/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 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 | UISupportedInterfaceOrientations~ipad
38 |
39 | UIInterfaceOrientationPortrait
40 | UIInterfaceOrientationPortraitUpsideDown
41 | UIInterfaceOrientationLandscapeLeft
42 | UIInterfaceOrientationLandscapeRight
43 |
44 | NSAppTransportSecurity
45 |
46 | NSAllowsArbitraryLoads
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
3 |
4 | apply( from = "../../../shared.gradle.kts")
5 |
6 | val kotlinXCoroutinesCore : String by extra
7 | val ktorClientIos : String by extra
8 | val kotlinXSerializationRuntime : String by extra
9 | val ktorClientCore : String by extra
10 | val ktorClientJson : String by extra
11 | val ktorClientSerialization : String by extra
12 |
13 | val clientSharedProject : ()->ProjectDependency by extra
14 | val sharedProject : ()->ProjectDependency by extra
15 |
16 | val isIosDevice : Boolean by extra
17 |
18 | plugins {
19 | id("org.jetbrains.kotlin.multiplatform")
20 | }
21 |
22 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
23 |
24 | configurations {
25 | val metadataCompileClasspath by getting {
26 | attributes { attribute(frameworkAttribute, "ios") }
27 | }
28 | }
29 |
30 | kotlin {
31 | val iosTarget = if(isIosDevice) iosArm64("ios") else iosX64("ios")
32 | iosTarget.apply {
33 | binaries {
34 | framework {
35 | if (!isIosDevice) {
36 | embedBitcode("disable")
37 | }
38 | }
39 | }
40 | attributes { attribute(frameworkAttribute, "ios") }
41 | }
42 |
43 | targets {
44 | // Target setup
45 | }
46 |
47 | sourceSets {
48 |
49 | val commonMain by getting {
50 | dependencies {
51 | implementation(project(":client-shared"))
52 | implementation(project(":shared"))
53 |
54 | implementation(ktorClientCore)
55 | implementation(ktorClientJson)
56 | implementation(kotlinXSerializationRuntime)
57 | }
58 | }
59 |
60 | val iosMain by getting {
61 |
62 | dependencies {
63 |
64 | implementation(kotlinXCoroutinesCore)
65 |
66 | implementation(kotlinXSerializationRuntime)
67 |
68 | implementation(ktorClientIos)
69 | implementation(ktorClientJson)
70 | implementation(ktorClientSerialization)
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/src/iosMain/kotlin/example/AppDelegate.kt:
--------------------------------------------------------------------------------
1 |
2 | package example
3 |
4 | import kotlinx.serialization.ImplicitReflectionSerializer
5 | import kotlinx.serialization.UnstableDefault
6 | import org.chrishatton.example.client
7 | import platform.UIKit.*
8 |
9 | class AppDelegate : UIResponder, UIApplicationDelegateProtocol {
10 |
11 | companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {
12 | val instance : AppDelegate get() = UIApplication.sharedApplication.delegate as AppDelegate
13 | }
14 |
15 | @OverrideInit
16 | constructor() : super()
17 |
18 | private var _window: UIWindow? = null
19 | override fun window() = _window
20 | override fun setWindow(window: UIWindow?) { _window = window }
21 |
22 | @UnstableDefault
23 | @ImplicitReflectionSerializer
24 | override fun applicationDidFinishLaunching(application: UIApplication) {
25 | println("Startup")
26 | }
27 |
28 | override fun applicationWillTerminate(application: UIApplication) {
29 | client.close()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/src/iosMain/kotlin/example/BaseViewAdapter.kt:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import kotlinx.coroutines.ExperimentalCoroutinesApi
4 | import kotlinx.coroutines.InternalCoroutinesApi
5 | import org.chrishatton.multimvp.ui.Contract.Presenter as Presenter
6 | import org.chrishatton.multimvp.ui.Contract.View as View
7 |
8 | /**
9 | * We would prefer to use a BaseViewController but 'Non-final Kotlin subclasses of Objective-C classes are not yet supported'
10 | * TODO: Refactor if/when this feature becomes available
11 | * Using this for now to satisfy *some* UIViewController boilerplate.
12 | */
13 | @ExperimentalCoroutinesApi
14 | @InternalCoroutinesApi
15 | abstract class BaseViewAdapter<
16 | Self:BaseViewAdapter,
17 | VC: View,
18 | PC: Presenter
19 | > : View {
20 |
21 | fun viewWillAppear(animated: Boolean) {
22 | val somePresenter : PC = presenter
23 | somePresenter.start()
24 | }
25 |
26 | fun viewDidDisappear(animated: Boolean) {
27 | presenter.stop()
28 | }
29 | }
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/src/iosMain/kotlin/example/FirstViewController.kt:
--------------------------------------------------------------------------------
1 |
2 | package example
3 |
4 | import kotlinx.cinterop.ExportObjCClass
5 | import kotlinx.cinterop.ObjCAction
6 | import kotlinx.cinterop.ObjCOutlet
7 | import kotlinx.coroutines.ExperimentalCoroutinesApi
8 | import kotlinx.coroutines.FlowPreview
9 | import kotlinx.coroutines.InternalCoroutinesApi
10 | import kotlinx.coroutines.MainScope
11 | import org.chrishatton.example.ui.FirstPresenter
12 | import org.chrishatton.multimvp.ui.Cycleable
13 | import org.chrishatton.multimvp.ui.CycleableMixIn
14 | import org.chrishatton.example.ui.FirstContract.Presenter as Presenter
15 | import org.chrishatton.example.ui.FirstContract.View as View
16 | import platform.Foundation.NSCoder
17 | import platform.UIKit.UIButton
18 | import platform.UIKit.UILabel
19 | import platform.UIKit.UITextField
20 | import platform.UIKit.UIViewController
21 |
22 | @FlowPreview
23 | @ExperimentalCoroutinesApi
24 | @ExportObjCClass
25 | @InternalCoroutinesApi
26 | class FirstViewController : UIViewController {
27 |
28 | @OverrideInit
29 | constructor(coder: NSCoder) : super(coder = coder)
30 |
31 | @ObjCOutlet
32 | lateinit var label: UILabel
33 |
34 | @ObjCOutlet
35 | lateinit var textField: UITextField
36 |
37 | @ObjCOutlet
38 | lateinit var button: UIButton
39 |
40 | override fun viewDidLoad() {
41 | super.viewDidLoad()
42 | println("viewDidLoad")
43 | }
44 |
45 | @ObjCAction
46 | fun buttonPressed() {
47 | viewAdapter.presenter.didSetName(name = textField.text ?: "")
48 | }
49 |
50 | private val viewAdapter = FirstViewAdapter()
51 |
52 | @FlowPreview
53 | inner class FirstViewAdapter : BaseViewAdapter(), View,
54 | Cycleable by CycleableMixIn(scopeCreator = ::MainScope) {
55 |
56 | override fun displayGreeting(text: String) {
57 | label.text = text
58 | }
59 |
60 | override val presenter: FirstPresenter by lazy {
61 | println("Heya!")
62 | FirstPresenter(
63 | baseUrl = "http://localhost:8080",
64 | view = this
65 | )
66 | }
67 | }
68 |
69 | override fun viewWillAppear(animated: Boolean) {
70 | super.viewWillAppear(animated)
71 | viewAdapter.viewWillAppear(animated)
72 | }
73 |
74 | override fun viewDidDisappear(animated: Boolean) {
75 | viewAdapter.viewDidDisappear(animated)
76 | super.viewDidDisappear(animated)
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/Code/Client/iOS/Example/src/iosMain/kotlin/main.kt:
--------------------------------------------------------------------------------
1 |
2 | import kotlinx.cinterop.*
3 | import platform.Foundation.*
4 | import platform.UIKit.*
5 | import example.*
6 |
7 | fun main(args: Array) {
8 | memScoped {
9 | val argc = args.size + 1
10 | val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues()
11 |
12 | autoreleasepool {
13 | UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate))
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/build.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 |
4 | apply( from = "../../../shared.gradle.kts")
5 |
6 | val kotlinSerializationPlugin : String by extra
7 | val kotlinGradlePlugin : String by extra
8 |
9 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
10 | repositories(configureSharedRepositories)
11 |
12 | dependencies {
13 | classpath(kotlinGradlePlugin)
14 | classpath(kotlinSerializationPlugin)
15 | }
16 | }
17 |
18 | plugins {
19 | id("com.android.library") apply false
20 | }
21 |
22 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
23 | repositories(configureSharedRepositories)
24 |
25 | allprojects {
26 | repositories(configureSharedRepositories)
27 | }
28 |
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Client/iOS/SupportingFiles/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
6 |
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/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 |
--------------------------------------------------------------------------------
/Code/Client/iOS/SupportingFiles/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.io.File
2 |
3 |
4 | apply( from = "../../client-shared.settings.gradle.kts" )
5 |
6 | rootProject.name = "client-ios"
7 |
8 | include(":example")
9 | project(":example").projectDir = file("../Example")
10 |
11 |
--------------------------------------------------------------------------------
/Code/README.md:
--------------------------------------------------------------------------------
1 |
2 | The Gradle project in this folder provides tasks to build and test the entire Application (Server & Clients).
3 | It is intended to be used from the command-line, specifically by the GitLab CI runner.
4 |
5 | It is *not* intended do be opened by an IDE.
6 | Development Environments should open a specific Client or Server project folder.
--------------------------------------------------------------------------------
/Code/Server/.gitignore:
--------------------------------------------------------------------------------
1 | /.gradle
2 | /.idea
3 | /out
4 | /build
5 | *.iml
6 | *.ipr
7 | *.iws
8 | local.properties
9 |
10 |
--------------------------------------------------------------------------------
/Code/Server/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import com.android.build.gradle.internal.coverage.JacocoReportTask
2 |
3 | /**
4 | *
5 | * Build file for the 'Server' module of this Kotlin Multi-platform Application.
6 | *
7 | */
8 |
9 | buildscript {
10 |
11 | apply(from = "../shared.gradle.kts")
12 |
13 | val kotlinVersion : String by extra
14 | val androidGradlePlugin : String by extra
15 | val kotlinSerializationPlugin : String by extra
16 |
17 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
18 | repositories(configureSharedRepositories)
19 |
20 | allprojects {
21 | repositories(configureSharedRepositories)
22 | }
23 |
24 | dependencies {
25 | // This should not be required as this is *not* an Android project.
26 | // Seems to be a current limitation of dependency on MPP project?
27 | classpath(kotlin("gradle-plugin", version = kotlinVersion))
28 | classpath(androidGradlePlugin)
29 | classpath(kotlinSerializationPlugin)
30 | }
31 | }
32 |
33 | val kotlinXSerializationRuntime : String by extra
34 |
35 | val ktorServerServlet : String by extra
36 | val ktorServerNetty : String by extra
37 | val ktorServerCore : String by extra
38 | val ktorLocations : String by extra
39 | val ktorServerSessions : String by extra
40 | val ktorAuth : String by extra
41 | val ktorWebsockets : String by extra
42 | val ktorSerialization : String by extra
43 |
44 | val logBackClassic : String by extra
45 |
46 | val ktorServerTests : String by extra
47 |
48 | val sharedProject : ()->ProjectDependency by extra
49 |
50 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
51 | repositories(configureSharedRepositories)
52 |
53 | allprojects {
54 | repositories(configureSharedRepositories)
55 | }
56 |
57 | plugins {
58 | application
59 | kotlin("jvm")
60 | war
61 | id("org.gretty") version "3.0.3"
62 | id("org.jetbrains.dokka") version "0.9.18"
63 | id("kotlinx-serialization") version "1.3.72"
64 | id("jacoco")
65 | }
66 |
67 | group = "Server"
68 | version = "0.0.1"
69 |
70 | application {
71 | mainClassName = "io.ktor.server.netty.EngineMain"
72 | }
73 |
74 | gretty {
75 | webXml = "web.xml"
76 | contextPath = "/"
77 | logbackConfigFile = "resources/logback.xml"
78 | }
79 |
80 | war {
81 | webAppDirName = "webapp"
82 | }
83 |
84 | tasks.dokka {
85 | moduleName = "server"
86 | outputFormat = "html"
87 | outputDirectory = "$buildDir/javadoc"
88 | }
89 |
90 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
91 |
92 | configurations {
93 | val compileClasspath by getting
94 | val testCompileClasspath by getting
95 | val runtimeClasspath by getting
96 | val testRuntimeClasspath by getting
97 |
98 | listOf(compileClasspath,testCompileClasspath,runtimeClasspath,testRuntimeClasspath).forEach { configuration ->
99 | configuration.attributes { attribute(frameworkAttribute, "server") }
100 | }
101 | }
102 |
103 | dependencies {
104 |
105 | implementation(project(path = ":shared")) { attributes { attribute(frameworkAttribute, "server") } }
106 |
107 | implementation(kotlinXSerializationRuntime)
108 |
109 | implementation(ktorServerServlet)
110 | implementation(ktorServerNetty)
111 | implementation(ktorServerCore)
112 | implementation(ktorLocations)
113 | implementation(ktorServerSessions)
114 | implementation(ktorAuth)
115 | implementation(ktorWebsockets)
116 | implementation(ktorSerialization)
117 | implementation(logBackClassic)
118 |
119 | testCompile(ktorServerTests)
120 | }
121 |
122 | tasks.jacocoTestReport {
123 | reports {
124 | xml.isEnabled = false
125 | csv.isEnabled = false
126 | html.destination = file("$buildDir/jacocoHtml")
127 | }
128 | }
129 |
130 | tasks["check"].dependsOn(tasks["jacocoTestReport"])
131 |
132 |
--------------------------------------------------------------------------------
/Code/Server/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
--------------------------------------------------------------------------------
/Code/Server/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Server/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/Server/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/Code/Server/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin, switch paths to Windows format before running java
129 | if $cygwin ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=$((i+1))
158 | done
159 | case $i in
160 | (0) set -- ;;
161 | (1) set -- "$args0" ;;
162 | (2) set -- "$args0" "$args1" ;;
163 | (3) set -- "$args0" "$args1" "$args2" ;;
164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=$(save "$@")
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
185 | cd "$(dirname "$0")"
186 | fi
187 |
188 | exec "$JAVACMD" "$@"
189 |
--------------------------------------------------------------------------------
/Code/Server/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem http://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/Code/Server/settings.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 |
3 | apply( from = "../shared.settings.gradle.kts" )
4 |
5 | rootProject.name = "Server"
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Code/Server/src/main/kotlin/example/Application.kt:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import io.ktor.application.Application
4 | import io.ktor.application.call
5 | import io.ktor.application.install
6 | import io.ktor.auth.Authentication
7 | import io.ktor.features.*
8 | import io.ktor.http.cio.websocket.Frame
9 | import io.ktor.http.cio.websocket.readText
10 | import io.ktor.locations.KtorExperimentalLocationsAPI
11 | import io.ktor.locations.Locations
12 | import io.ktor.response.respond
13 | import io.ktor.response.respondText
14 | import io.ktor.routing.get
15 | import io.ktor.routing.post
16 | import io.ktor.routing.routing
17 | import io.ktor.serialization.json
18 | import io.ktor.server.netty.EngineMain
19 | import io.ktor.sessions.Sessions
20 | import io.ktor.websocket.webSocket
21 | import org.chrishatton.example.model.Person
22 |
23 | fun main(args: Array): Unit = EngineMain.main(args)
24 |
25 | /**
26 | * To run start with Gretty Gradle task 'appStartWar'.
27 | * To debug start 'appStartWarDebug' and attach debugger on 5005 when execution first pauses.
28 | */
29 | @KtorExperimentalLocationsAPI
30 | @Suppress("unused") // Referenced in application.conf
31 | @kotlin.jvm.JvmOverloads
32 | fun Application.module(testing: Boolean = false) {
33 |
34 | install(CallLogging)
35 |
36 | install(ContentNegotiation) {
37 | json()
38 | }
39 |
40 | install(Locations) {
41 | }
42 |
43 | install(Sessions) {
44 | //cookie("MY_SESSION") {
45 | // cookie.extensions["SameSite"] = "lax"
46 | //}
47 | }
48 |
49 | install(Compression) {
50 | gzip {
51 | priority = 1.0
52 | }
53 | deflate {
54 | priority = 10.0
55 | minimumSize(1024) // condition
56 | }
57 | }
58 |
59 | install(AutoHeadResponse)
60 |
61 | install(DefaultHeaders) {
62 | header("X-Engine", "Ktor") // will send this header with each response
63 | }
64 |
65 | install(Authentication) {
66 | }
67 |
68 | install(io.ktor.websocket.WebSockets) {
69 | // pingPeriod = Duration.ofSeconds(15)
70 | // timeout = Duration.ofSeconds(15)
71 | maxFrameSize = Long.MAX_VALUE
72 | masking = false
73 | }
74 |
75 | routing {
76 | get("/") {
77 | call.respondText("HELLO WORLD!")
78 | }
79 |
80 | webSocket("/server/echo") {
81 | send(Frame.Text("Hi from server"))
82 | while (true) {
83 | val frame = incoming.receive()
84 | if (frame is Frame.Text) {
85 | send(Frame.Text("Client said: " + frame.readText()))
86 | }
87 | }
88 | }
89 |
90 | post("/person") { person:Person ->
91 | val acquaintedPerson = Person("Mark", "Halliwell")
92 | println("I think ${person.fullName} might know ${acquaintedPerson.fullName}")
93 | call.respond(acquaintedPerson)
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/Code/Server/src/main/resources/application.conf:
--------------------------------------------------------------------------------
1 | ktor {
2 | deployment {
3 | port = 8080
4 | }
5 | application {
6 | modules = [ example.ApplicationKt.module ]
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/Code/Server/src/main/resources/logback.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | %d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Code/Server/src/test/kotlin/example/ApplicationTest.kt:
--------------------------------------------------------------------------------
1 | package example
2 |
3 | import io.ktor.http.HttpMethod
4 | import io.ktor.http.HttpStatusCode
5 | import io.ktor.server.testing.handleRequest
6 | import io.ktor.server.testing.withTestApplication
7 | import kotlin.test.Test
8 | import kotlin.test.assertEquals
9 |
10 | class ApplicationTest {
11 | @Test
12 | fun testRoot() {
13 | withTestApplication({ module(testing = true) }) {
14 | handleRequest(HttpMethod.Get, "/").apply {
15 | assertEquals(HttpStatusCode.OK, response.status())
16 | assertEquals("HELLO WORLD!", response.content)
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Code/Server/webapp/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 | io.ktor.ktor.config
11 | application.conf
12 |
13 |
14 |
15 | KtorServlet
16 | KtorServlet
17 | io.ktor.server.servlet.ServletApplicationEngine
18 |
19 |
20 | true
21 |
22 |
23 |
24 | 304857600
25 | 304857600
26 | 0
27 |
28 |
29 |
30 |
31 | KtorServlet
32 | /
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Code/Shared/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 |
3 |
--------------------------------------------------------------------------------
/Code/Shared/build.gradle.kts:
--------------------------------------------------------------------------------
1 | import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetPreset
2 |
3 | /**
4 | *
5 | * Build file for the 'Shared' module of this Kotlin Multi-platform Application.
6 | *
7 | * Source files implemented in this module are accessible in the Server and Client projects.
8 | * It is particularly useful to implement Model files in Shared.
9 | *
10 | */
11 |
12 | buildscript {
13 |
14 | // Reads 'common.properties' into Gradle extra
15 | apply( from = "../shared.gradle.kts")
16 |
17 | val kotlinVersion : String by extra
18 | val kotlinSerializationPlugin : String by extra
19 |
20 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
21 | repositories(configureSharedRepositories)
22 |
23 | dependencies {
24 | classpath(kotlinSerializationPlugin)
25 | classpath(kotlin("gradle-plugin", version = kotlinVersion))
26 | }
27 | }
28 |
29 | val kotlinXSerializationRuntime : String by extra
30 | val kotlinXCoroutinesCore : String by extra
31 | val ktorServerSessions : String by extra
32 | val ktorAuth : String by extra
33 |
34 | val isIosDevice : Boolean by extra
35 |
36 | val isMinJava12 : Boolean = JavaVersion.current() >= JavaVersion.VERSION_12
37 |
38 | plugins {
39 | id("com.android.library")
40 | id("org.jetbrains.kotlin.multiplatform")
41 | id("kotlinx-serialization")
42 | }
43 |
44 | val configureSharedRepositories = extra["configureSharedRepositories"] as RepositoryHandler.()->Unit
45 | repositories(configureSharedRepositories)
46 |
47 | allprojects {
48 | repositories(configureSharedRepositories)
49 | }
50 |
51 | group = "org.chrishatton"
52 | version = "0.0.1"
53 |
54 | android {
55 | compileSdkVersion(29)
56 | defaultConfig {
57 | minSdkVersion(21)
58 | targetSdkVersion(29)
59 | versionCode = 1
60 | versionName = "1.0"
61 | }
62 | buildTypes {
63 | getByName("release") {
64 | isMinifyEnabled = false
65 | }
66 | }
67 |
68 | sourceSets {
69 | val main by getting {
70 | manifest.srcFile("src/androidMain/AndroidManifest.xml")
71 | java.srcDirs("src/androidMain/kotlin")
72 | res.srcDirs("src/androidMain/res")
73 | }
74 | val test by getting {
75 | java.srcDirs("src/androidTest/kotlin")
76 | res.srcDirs("src/androidTest/res")
77 | }
78 | }
79 | }
80 |
81 | val frameworkAttribute = Attribute.of("org.chrishatton.example.framework", String::class.java)
82 |
83 | kotlin {
84 |
85 | android("android") { attributes.attribute(frameworkAttribute, "android") }
86 |
87 | if(isMinJava12) {
88 | jvm("javafx") {attributes.attribute(frameworkAttribute, "javafx") }
89 | }
90 |
91 | jvm("server") {
92 | attributes.attribute(frameworkAttribute, "server")
93 | }
94 |
95 | val iosTarget = if(isIosDevice) iosArm64("ios") else iosX64("ios")
96 | iosTarget.apply {
97 | binaries {
98 | framework {
99 | if (!isIosDevice) {
100 | embedBitcode("disable")
101 | }
102 | }
103 | }
104 | attributes.attribute(frameworkAttribute, "ios")
105 | }
106 |
107 | js("browser",IR) {
108 | browser {
109 | }
110 | binaries.executable()
111 | attributes.attribute(frameworkAttribute, "js")
112 | }
113 |
114 | sourceSets {
115 |
116 | val commonMain by getting {
117 | dependencies {
118 | implementation(kotlinXSerializationRuntime)
119 | implementation(kotlinXCoroutinesCore)
120 | }
121 | }
122 | val commonTest by getting {
123 | dependencies {
124 | implementation(kotlin("test-common"))
125 | implementation(kotlin("test-annotations-common"))
126 | }
127 | }
128 |
129 | val androidMain by getting {
130 | dependencies {
131 | implementation(kotlinXSerializationRuntime)
132 | }
133 | }
134 | val androidTest by getting {
135 | dependencies {
136 | implementation(kotlin("test"))
137 | implementation(kotlin("test-junit"))
138 | }
139 | }
140 |
141 | if(isMinJava12) {
142 | val javafxMain by getting {
143 | dependencies {
144 | implementation(kotlinXSerializationRuntime)
145 | }
146 | }
147 | val javafxTest by getting {
148 | dependencies {
149 | implementation(kotlin("test"))
150 | implementation(kotlin("test-junit"))
151 | }
152 | }
153 | }
154 |
155 | val browserMain by getting {
156 | dependencies {
157 | implementation(kotlinXCoroutinesCore)
158 | implementation(kotlinXSerializationRuntime)
159 | }
160 | }
161 |
162 | val browserTest by getting {
163 | dependencies {
164 |
165 | }
166 | }
167 |
168 | val serverMain by getting {
169 | dependencies {
170 | implementation(kotlinXSerializationRuntime)
171 | }
172 | }
173 | val serverTest by getting {
174 | dependencies {
175 | implementation(kotlin("test"))
176 | implementation(kotlin("test-junit"))
177 | }
178 | }
179 |
180 | val iosMain by getting {
181 | dependencies {
182 | implementation(kotlinXCoroutinesCore)
183 | implementation(kotlinXSerializationRuntime)
184 | }
185 | }
186 | val iosTest by getting {
187 | }
188 | }
189 | }
190 |
--------------------------------------------------------------------------------
/Code/Shared/src/androidMain/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/Code/Shared/src/androidMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | actual typealias UUID = java.util.UUID
4 |
--------------------------------------------------------------------------------
/Code/Shared/src/androidTest/kotlin/org/chrishatton/example/SampleTestsJVM.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import kotlin.test.Test
4 |
5 | class SampleTestsJVM {
6 | @Test
7 | fun testHello() {
8 | //assertTrue("JVM" in hello())
9 | }
10 | }
--------------------------------------------------------------------------------
/Code/Shared/src/browserMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | actual typealias UUID = String
4 |
--------------------------------------------------------------------------------
/Code/Shared/src/commonMain/kotlin/org/chrishatton/example/model/Person.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | import kotlinx.serialization.Serializable
4 | import kotlinx.serialization.Transient
5 |
6 | @Serializable
7 | public data class Person(
8 | val names: List
9 | ) {
10 | constructor() : this(emptyList())
11 |
12 | constructor(vararg names: String) : this(names.toList())
13 |
14 | @Transient
15 | @kotlin.jvm.Transient
16 | val firstName : String? = names.firstOrNull()
17 |
18 | @Transient
19 | @kotlin.jvm.Transient
20 | val lastName : String? = if(names.size<2) null else names.last()
21 |
22 | @Transient
23 | @kotlin.jvm.Transient
24 | val firstLastName : String? = listOf(firstName,lastName).joinToString(" ")
25 |
26 | @Transient
27 | @kotlin.jvm.Transient
28 | val fullName : String? = names.joinToString(" ")
29 | }
30 |
--------------------------------------------------------------------------------
/Code/Shared/src/commonMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | expect class UUID
4 |
--------------------------------------------------------------------------------
/Code/Shared/src/commonMain/kotlin/org/chrishatton/example/model/api/CRUD.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model.api
2 |
3 | import org.chrishatton.example.model.UUID
4 |
5 | sealed class CRUD {
6 | data class Create (val `object`: T) : CRUD()
7 | data class Update (val `object`: T) : CRUD()
8 | data class Retrieve(val objectId: UUID) : CRUD()
9 | data class Delete (val objectId: UUID) : CRUD()
10 | }
11 |
--------------------------------------------------------------------------------
/Code/Shared/src/commonTest/kotlin/org/chrishatton/example/SharedCommonTests.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertTrue
5 |
6 | class SharedCommonTests {
7 | @Test
8 | fun testMe() {
9 | //assertTrue(Sample().checkMe() > 0)
10 | }
11 | }
--------------------------------------------------------------------------------
/Code/Shared/src/iosMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | import platform.Foundation.NSUUID
4 |
5 | actual typealias UUID = NSUUID
6 |
--------------------------------------------------------------------------------
/Code/Shared/src/iosTest/kotlin/org/chrishatton/example/SharediOSTests.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import kotlin.test.Test
4 | import kotlin.test.assertEquals
5 |
6 | class SharediOSTests {
7 | @Test
8 | fun testPlatform() {
9 | //assertEquals(expected = "iOS", actual = platformName)
10 | }
11 | }
--------------------------------------------------------------------------------
/Code/Shared/src/javafxMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | actual typealias UUID = java.util.UUID
4 |
--------------------------------------------------------------------------------
/Code/Shared/src/javafxTest/kotlin/org/chrishatton/example/SampleTestsJVM.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import kotlin.test.Test
4 |
5 | class SampleTestsJVM {
6 | @Test
7 | fun testHello() {
8 | //assertTrue("JVM" in hello())
9 | }
10 | }
--------------------------------------------------------------------------------
/Code/Shared/src/javafxTest/kotlin/org/chrishatton/example/package.kt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Shared/src/javafxTest/kotlin/org/chrishatton/example/package.kt
--------------------------------------------------------------------------------
/Code/Shared/src/serverMain/kotlin/org/chrishatton/example/model/UUID.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example.model
2 |
3 | actual typealias UUID = java.util.UUID
4 |
--------------------------------------------------------------------------------
/Code/Shared/src/serverTest/kotlin/org/chrishatton/example/SampleTestsJVM.kt:
--------------------------------------------------------------------------------
1 | package org.chrishatton.example
2 |
3 | import kotlin.test.Test
4 |
5 | class SampleTestsJVM {
6 | @Test
7 | fun testHello() {
8 | //assertTrue("JVM" in hello())
9 | }
10 | }
--------------------------------------------------------------------------------
/Code/Shared/src/serverTest/kotlin/org/chrishatton/example/package.kt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/Shared/src/serverTest/kotlin/org/chrishatton/example/package.kt
--------------------------------------------------------------------------------
/Code/build.gradle.kts:
--------------------------------------------------------------------------------
1 | tasks {
2 |
3 | register("buildApp") {
4 | //dependsOn(gradle.includedBuild("android").task(":assemble" ))
5 | dependsOn(gradle.includedBuild("desktop").task(":runtimeZip"))
6 | //dependsOn(gradle.includedBuild("ios" ).task(":build" ))
7 | dependsOn(gradle.includedBuild("server" ).task(":war" ))
8 | }
9 |
10 | // register("publishMultiMvpLib",GradleBuild::class) {
11 |
12 | // this.dir = file("Lib/multi-mvp")
13 | // this.tasks = listOf("publish")
14 | // }
15 |
16 | // register("publishCoroutinesUiLib",GradleBuild::class) {
17 | // this.dir = file("Lib/coroutines-ui")
18 | // this.tasks = listOf("publish")
19 | // }
20 |
21 | // register("publishLibs") {
22 | // dependsOn("publishMultiMvpLib", "publishCoroutinesUiLib")
23 | // }
24 | }
25 |
26 |
27 | // /**
28 | // * The approach taken in this file is an attempt to maximise the efficiency of
29 | // * building by a GradleBuild task-per-platform.
30 | // *
31 | // * That approach itself is known not to be the most efficient way of building
32 | // * the entire project; since Gradle cannot consider the whole task-graph across
33 | // * each GradleBuild invocation, leading to repeat builds of shared libraries.
34 | // * The most efficient outcome would be to write an overarching Gradle project
35 | // * which treats each Platform as a sub-project.
36 | // * I experimented with this in a previous commit but it has complications and I
37 | // * want to move ahead with other aspects of the Template development.
38 | // * The best-compromise approach here collects all the tasks demanded of the
39 | // * current whole-App build to at least ensure only one GradleBuild invocation per
40 | // * Platform with, say, the tasks for testing and deploying a given platform
41 | // * unified into it's own task graph.
42 | // * This is particularly useful when on a Development machine I may wish to
43 | // * invoke just the Unit Tests for a whole platform, while on a CI box (where
44 | // * repeated overall Gradle invocations are costly due to Daemon startup and
45 | // * Cache Storage/Retrieval) it is preferable to have build, test and deploy
46 | // * all handled in a single Gradle invocation (albeit multi-GradleBuild).
47 | // */
48 |
49 | // // The exclusion of 'lint' and 'lintVitalRelease' to disable lint are *not* desired.
50 | // // Currently necessary due to issue: https://youtrack.jetbrains.com/issue/KT-27170
51 | // // Re-enable lint when this issue is resolved.
52 | // enum class Platform(
53 | // val identifier:String,
54 | // val dirPath:String,
55 | // vararg val excludedTaskNames: String
56 | // ) {
57 | // Android("Android","Client/Android", "lint","lintVitalRelease"),
58 | // Desktop("Desktop","Client/Desktop"),
59 | // Ios ("Ios","Client/iOS/SupportingFiles"),
60 | // Server ("Server","Server")
61 | // }
62 |
63 | // /**
64 | // * The Gradle task to invoke for testing of each of the Platform components
65 | // */
66 | // val testTasks : Map = mapOf(
67 | // Platform.Android to "check",
68 | // Platform.Desktop to "check",
69 | // Platform.Ios to "check",
70 | // Platform.Server to "check"
71 | // )
72 |
73 | // /**
74 | // * The Gradle task to invoke for fully building deployable artifacts for each of the Platform components
75 | // */
76 | // val buildTasks : Map = mapOf(
77 | // Platform.Android to "assemble",
78 | // Platform.Desktop to "runtimeZip",
79 | // Platform.Ios to "build",
80 | // Platform.Server to "war"
81 | // )
82 |
83 | // /**
84 | // * The Gradle task to invoke for fully cleaning deployable artifacts for each of the Platform components
85 | // */
86 | // val cleanTasks : Map = mapOf(
87 | // Platform.Android to "clean",
88 | // Platform.Desktop to "clean",
89 | // Platform.Ios to "clean",
90 | // Platform.Server to "clean"
91 | // )
92 |
93 | // /**
94 | // * The Gradle task to invoke for deploying the artifacts produced by `buildTasks`.
95 | // * Does not depend on buildTasks so assumes that buildTasks has been independently run
96 | // * beforehand, leaving the artifacts available in the filesystem.
97 | // */
98 | // val deployOnlyTasks : Map = mapOf(
99 | // )
100 |
101 | // fun collectPlatformTaskNames(vararg platformTasksList: Map) : Map>
102 | // = platformTasksList.map{it.entries}.reduce{a,b->a+b}.groupBy({it.key},{it.value})
103 |
104 | // fun registerPlatformTasks(name:String,appBuildTaskNames: Map>) {
105 | // val platformBuildTasks : List = appBuildTaskNames.mapNotNull { (platform,tasks) ->
106 | // if(tasks.isEmpty()) return@mapNotNull null
107 | // project.tasks.create(name+platform.identifier,GradleBuild::class) {
108 | // this.dir = file(platform.dirPath)
109 | // this.startParameter.setExcludedTaskNames(platform.excludedTaskNames.asIterable())
110 | // this.tasks = tasks
111 | // }
112 | // }
113 | // project.tasks.register(name,Task::class) {
114 | // setDependsOn(platformBuildTasks)
115 | // }
116 | // }
117 |
118 | // registerPlatformTasks("buildApp", collectPlatformTaskNames(buildTasks))
119 | // registerPlatformTasks("testApp", collectPlatformTaskNames(testTasks))
120 | // registerPlatformTasks("buildAndTestApp", collectPlatformTaskNames(buildTasks,testTasks))
121 | // registerPlatformTasks("deployOnlyApp", collectPlatformTaskNames(deployOnlyTasks))
122 | // registerPlatformTasks("cleanApp", collectPlatformTaskNames(cleanTasks))
123 |
124 | // tasks {
125 |
126 | // register("publishMultiMvpLib",GradleBuild::class) {
127 | // this.dir = file("Lib/multi-mvp")
128 | // this.tasks = listOf("publish")
129 | // }
130 |
131 | // register("publishCoroutinesUiLib",GradleBuild::class) {
132 | // this.dir = file("Lib/coroutines-ui")
133 | // this.tasks = listOf("publish")
134 | // }
135 |
136 | // register("publishLibs") {
137 | // dependsOn("publishMultiMvpLib", "publishCoroutinesUiLib")
138 | // }
139 | // }
140 |
141 |
--------------------------------------------------------------------------------
/Code/gradle.properties:
--------------------------------------------------------------------------------
1 | # Gradle
2 | org.gradle.jvmargs=-Xmx12g -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
3 | org.gradle.parallel=true
4 | org.gradle.caching=true
5 | org.gradle.configureondemand=false
6 |
7 | # Kotlin
8 | kotlin.code.style=official
9 | kotlin.parallel.tasks.in.project=true
10 | kotlin.native.disableCompilerDaemon=true
11 | kotlin.mpp.enableGranularSourceSetsMetadata=true
12 |
13 | #Android
14 | android.useAndroidX=true
15 | android.enableJetifier=false
16 |
--------------------------------------------------------------------------------
/Code/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/chris-hatton/kotlin-multiplatform-template/26dc1b5b1df888167f0b4af7fd74b039a4a574c3/Code/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/Code/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/Code/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 | # Determine the Java command to use to start the JVM.
86 | if [ -n "$JAVA_HOME" ] ; then
87 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
88 | # IBM's JDK on AIX uses strange locations for the executables
89 | JAVACMD="$JAVA_HOME/jre/sh/java"
90 | else
91 | JAVACMD="$JAVA_HOME/bin/java"
92 | fi
93 | if [ ! -x "$JAVACMD" ] ; then
94 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
95 |
96 | Please set the JAVA_HOME variable in your environment to match the
97 | location of your Java installation."
98 | fi
99 | else
100 | JAVACMD="java"
101 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
102 |
103 | Please set the JAVA_HOME variable in your environment to match the
104 | location of your Java installation."
105 | fi
106 |
107 | # Increase the maximum file descriptors if we can.
108 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
109 | MAX_FD_LIMIT=`ulimit -H -n`
110 | if [ $? -eq 0 ] ; then
111 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
112 | MAX_FD="$MAX_FD_LIMIT"
113 | fi
114 | ulimit -n $MAX_FD
115 | if [ $? -ne 0 ] ; then
116 | warn "Could not set maximum file descriptor limit: $MAX_FD"
117 | fi
118 | else
119 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
120 | fi
121 | fi
122 |
123 | # For Darwin, add options to specify how the application appears in the dock
124 | if $darwin; then
125 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
126 | fi
127 |
128 | # For Cygwin, switch paths to Windows format before running java
129 | if $cygwin ; then
130 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
131 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
132 | JAVACMD=`cygpath --unix "$JAVACMD"`
133 |
134 | # We build the pattern for arguments to be converted via cygpath
135 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
136 | SEP=""
137 | for dir in $ROOTDIRSRAW ; do
138 | ROOTDIRS="$ROOTDIRS$SEP$dir"
139 | SEP="|"
140 | done
141 | OURCYGPATTERN="(^($ROOTDIRS))"
142 | # Add a user-defined pattern to the cygpath arguments
143 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
144 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
145 | fi
146 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
147 | i=0
148 | for arg in "$@" ; do
149 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
150 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
151 |
152 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
153 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
154 | else
155 | eval `echo args$i`="\"$arg\""
156 | fi
157 | i=$((i+1))
158 | done
159 | case $i in
160 | (0) set -- ;;
161 | (1) set -- "$args0" ;;
162 | (2) set -- "$args0" "$args1" ;;
163 | (3) set -- "$args0" "$args1" "$args2" ;;
164 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
165 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
166 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
167 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
168 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
169 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
170 | esac
171 | fi
172 |
173 | # Escape application args
174 | save () {
175 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
176 | echo " "
177 | }
178 | APP_ARGS=$(save "$@")
179 |
180 | # Collect all arguments for the java command, following the shell quoting and substitution rules
181 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
182 |
183 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
184 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
185 | cd "$(dirname "$0")"
186 | fi
187 |
188 | exec "$JAVACMD" "$@"
189 |
--------------------------------------------------------------------------------
/Code/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
33 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
34 |
35 | @rem Find java.exe
36 | if defined JAVA_HOME goto findJavaFromJavaHome
37 |
38 | set JAVA_EXE=java.exe
39 | %JAVA_EXE% -version >NUL 2>&1
40 | if "%ERRORLEVEL%" == "0" goto init
41 |
42 | echo.
43 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
44 | echo.
45 | echo Please set the JAVA_HOME variable in your environment to match the
46 | echo location of your Java installation.
47 |
48 | goto fail
49 |
50 | :findJavaFromJavaHome
51 | set JAVA_HOME=%JAVA_HOME:"=%
52 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
53 |
54 | if exist "%JAVA_EXE%" goto init
55 |
56 | echo.
57 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
58 | echo.
59 | echo Please set the JAVA_HOME variable in your environment to match the
60 | echo location of your Java installation.
61 |
62 | goto fail
63 |
64 | :init
65 | @rem Get command-line arguments, handling Windows variants
66 |
67 | if not "%OS%" == "Windows_NT" goto win9xME_args
68 |
69 | :win9xME_args
70 | @rem Slurp the command line arguments.
71 | set CMD_LINE_ARGS=
72 | set _SKIP=2
73 |
74 | :win9xME_args_slurp
75 | if "x%~1" == "x" goto execute
76 |
77 | set CMD_LINE_ARGS=%*
78 |
79 | :execute
80 | @rem Setup the command line
81 |
82 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
83 |
84 | @rem Execute Gradle
85 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
86 |
87 | :end
88 | @rem End local scope for the variables with windows NT shell
89 | if "%ERRORLEVEL%"=="0" goto mainEnd
90 |
91 | :fail
92 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
93 | rem the _cmd.exe /c_ return code!
94 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
95 | exit /b 1
96 |
97 | :mainEnd
98 | if "%OS%"=="Windows_NT" endlocal
99 |
100 | :omega
101 |
--------------------------------------------------------------------------------
/Code/local.properties.template:
--------------------------------------------------------------------------------
1 |
2 | # Local Environment Properties for the Multiplatform Template Project
3 | #
4 | # This file must be copied (or renamed) to `local.properties` and
5 | # then edited to correct values.
6 | #
7 | # See the 'Getting Starting' page at:
8 | # https://git.chrishatton.org/chris/kotlin-multiplatform-template/wikis/Getting-Started
9 |
10 | # Android Settings
11 | sdk.dir=
12 | ndk.dir=
13 |
14 | # JavaFX Settings
15 | jdkFxPlatformsHome=
16 | javaFxSdkHome=
17 |
18 | # Library Publishing Settings
19 | bintray.user=
20 | bintray.key=
21 | bintray.repo=
22 | bintray.userEmail=
23 | publish.vcsUrl=
24 | publish.author=
25 |
--------------------------------------------------------------------------------
/Code/settings.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | rootProject.name = "Multiplatform-Template"
3 |
4 | includeBuild("Client/Android" ) { name = "android" }
5 | includeBuild("Client/Desktop" ) { name = "desktop" }
6 | includeBuild("Client/iOS/SupportingFiles" ) { name = "ios" }
7 | includeBuild("Server" ) { name = "server" }
8 |
9 | //includeBuild("Server" ) { name = "server" }
10 |
--------------------------------------------------------------------------------
/Code/shared.gradle.kts:
--------------------------------------------------------------------------------
1 | import java.util.*
2 | import java.util.Locale
3 |
4 | /**
5 | * This script is applied by the build-scripts of every sub-project in the Multi-Platform template project.
6 | * It provides these centralized functions:
7 | * - Dependency versions; where one file 'shared.properties' sets dependency versions for the entire project.
8 | * - Determines the Operating System; whether the build is occurring on Linux/Mac/Windows.
9 | */
10 |
11 | /**
12 | * Determine the current operating system - used by jpackage task
13 | */
14 | val os : String = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH)
15 | extra["currentOs"] = when {
16 | ((os.indexOf("mac") >= 0) || (os.indexOf("darwin") >= 0)) -> "osx"
17 | (os.indexOf("win") >= 0) -> "windows"
18 | (os.indexOf("nux") >= 0) -> "linux"
19 | else -> throw Exception("Unsupported operating system: '$os'")
20 | }
21 |
22 | /**
23 | * Load entries from 'shared.properties' into the context Gradle project's 'extra' properties.
24 | *
25 | * This is used to keep Kotlin language, Ktor and other library dependencies consistent across
26 | * several Multi-platform sub-projects.
27 | *
28 | * Even when referencing dependencies centrally in this way, version numbers which are common to families
29 | * of dependencies e.g. multi-platform Ktor components, would require repetition and maintenance.
30 | *
31 | * So, to ease maintenance of dependencies referenced in 'shared.properties', substitutions in the familiar
32 | * form '$token' are also resolved by this loading code, where 'token' may be the key of another value in the
33 | * 'shared.properties' file.
34 | *
35 | * e.g.
36 | * myVersion = 1.2.0
37 | * myDependency = myGroup:myId:$myVersion
38 | *
39 | * ...gets loaded as:
40 | * myVersion = 1.2.0
41 | * myDependency = myGroup:myId:1.2.0
42 | */
43 | fun loadSubstitutedPropertiesToExtra(fileName: String) {
44 |
45 | // Load the properties file without substitutions
46 | val properties = Properties().apply {
47 | File(fileName).inputStream().use { fis ->
48 | load(fis)
49 | }
50 | }
51 |
52 | // Define recursive substitution by $token
53 | fun getResolved(key: String) : String? {
54 |
55 | val substituteRegex = Regex("\\\$([A-Za-z_0-9]+)")
56 |
57 | fun substitute(value: String) : String {
58 | var resolvingValue : String = value
59 | do {
60 | val lastValue = resolvingValue
61 | resolvingValue = substituteRegex.replace(value) { result ->
62 | val substitutionKey : String = result.groupValues[1]
63 | getResolved(substitutionKey) ?: throw Exception("Couldn't find substitution for key '$substitutionKey'")
64 | }
65 | } while(lastValue != resolvingValue) // Iteratively resolve until the string stabilises
66 | return resolvingValue
67 | }
68 |
69 | val unsubbedValue : String = properties.get(key) as? String ?: return null
70 | return substitute(value = unsubbedValue)
71 | }
72 |
73 | // Copy resolved values into Gradle 'extra'
74 | val extraValues = properties.map { (key,_) ->
75 | val resolvedValue = getResolved(key as String)
76 | key.toString() to resolvedValue
77 | }.toMap()
78 |
79 | //val pad : Int = extraValues.keys.map { it.length }.max() ?: 0
80 |
81 | extraValues.entries
82 | .sortedBy { (key,_)-> key }
83 | .forEach { (key, value) ->
84 | //println("${key.padEnd(pad)} = $value")
85 | extra[key] = value
86 | }
87 | }
88 |
89 | loadSubstitutedPropertiesToExtra(fileName = buildscript.sourceFile!!.parent + "/shared.properties")
90 |
91 | val localPropertiesFilename = buildscript.sourceFile!!.parent + "/local.properties"
92 | val localPropertiesFile = File(localPropertiesFilename)
93 | if(localPropertiesFile.exists()) {
94 | loadSubstitutedPropertiesToExtra(fileName = localPropertiesFilename)
95 | }
96 |
97 | // Define project dependencies by conventional module path
98 |
99 | extra["androidclientSharedProject"] = { project(":android-client-shared") } //as ()->ProjectDependency
100 | extra["clientSharedProject"] = { project(":client-shared") }
101 | extra["sharedProject"] = { project(":shared") }
102 |
103 | extra["isIosDevice"] = when(val id = System.getenv("PLATFORM_PREFERRED_ARCH")) {
104 | "arm64" -> true
105 | "X64" -> false
106 | else -> false
107 | }
108 |
109 | val configureSharedRepositories : RepositoryHandler.() -> Unit = {
110 |
111 | mavenLocal()
112 |
113 | google()
114 | jcenter()
115 |
116 | maven( url = "https://kotlin.bintray.com/kotlinx" )
117 | maven( url = "https://kotlin.bintray.com/kotlin/ktor" )
118 | maven( url = "https://plugins.gradle.org/m2/" )
119 |
120 | //maven( url = "https://oss.jfrog.org/oss-snapshot-local" ) { content { includeGroup("org.chrishatton") } }
121 | //maven( url = "https://dl.bintray.com/chris-hatton/lib" ) { content { includeGroup("org.chrishatton") } }
122 | }
123 |
124 | extra["configureSharedRepositories"] = configureSharedRepositories
125 |
126 | // Needed when required to use different Android/Gradle plugin versions between AS and IJ
127 | val isIntellij = System.getenv("XPC_SERVICE_NAME")?.contains("intellij") ?: false
128 | val androidGradlePluginVersion = if(isIntellij) {
129 | extra["androidGradlePluginVersionIntellijSafe"]
130 | } else {
131 | extra["androidGradlePluginVersionNormal"]
132 | }
133 | extra["androidGradlePlugin"] = "${extra["androidGradlePluginBase"]}:$androidGradlePluginVersion"
134 |
--------------------------------------------------------------------------------
/Code/shared.properties:
--------------------------------------------------------------------------------
1 |
2 | # This single file defines all Dependencies and their Versions
3 | # for the entire Multi-platform Template project
4 | #
5 | # The function used to read this file in `shared.gradle.kts` also
6 | # respects value-string substitutions in the format $key.
7 | # This allows us to reference e.g. $kotlinVersion across it's numerous modules.
8 |
9 | # Server logging
10 | logbackVersion = 1.2.3
11 |
12 | # Kotlin Settings
13 | kotlin.code.style = official
14 |
15 | # JavaFX
16 | javaFxGradlePluginVersion = 8.8.2
17 | javaFxPluginVersion = 0.0.8
18 | tornadoFxVersion = 2.0.0-SNAPSHOT
19 |
20 | androidGradlePluginBase = com.android.tools.build:gradle
21 | androidGradlePluginVersionNormal = 4.0.1
22 | androidGradlePluginVersionIntellijSafe = 3.6.2
23 |
24 | androidBuildToolsVersion = 29.0.2
25 | androidCompileSdkVersion = 29
26 | androidTargetSdkVersion = 29
27 | androidMinSdkVersion = 21
28 |
29 | # Gradle
30 | kotlinGradlePlugin = org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion
31 | androidGradleDokkaPlugin = org.jetbrains.dokka:dokka-android-gradle-plugin:0.9.18
32 | kotlinSerializationPlugin = org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion
33 |
34 |
35 | # Kotlin
36 |
37 | kotlinVersion = 1.4.10
38 |
39 | # Kotlin Coroutines
40 |
41 | coroutinesVersion = 1.3.9
42 |
43 | kotlinXCoroutinesCore = org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion
44 | kotlinXCoroutinesAndroid = org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion
45 | kotlinXCoroutinesJavaFx = org.jetbrains.kotlinx:kotlinx-coroutines-javafx:$coroutinesVersion
46 | kotlinXCoroutinesCoreJs = org.jetbrains.kotlinx:kotlinx-coroutines-js:$coroutinesVersion
47 |
48 | # Framework
49 | multiMvp = org.chrishatton:multi-mvp:0.1.1-SNAPSHOT
50 | coroutinesUi = org.chrishatton:coroutines-ui:0.1.1-SNAPSHOT
51 |
52 | # Kotlin Serialization
53 |
54 | serializationVersion = 1.0-M1-1.4.0-rc
55 |
56 | kotlinXSerializationRuntime = org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion
57 | kotlinXSerializationRuntimeJs = org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion
58 |
59 | # Ktor
60 |
61 | ktorVersion = 1.3.2-1.4.0-rc
62 |
63 | ktorClient = io.ktor:ktor-client:$ktorVersion
64 | ktorClientAndroid = io.ktor:ktor-client-android:$ktorVersion
65 | ktorClientIos = io.ktor:ktor-client-ios:$ktorVersion
66 | ktorClientCore = io.ktor:ktor-client-core:$ktorVersion
67 | ktorClientJson = io.ktor:ktor-client-json:$ktorVersion
68 | ktorClientSerialization = io.ktor:ktor-client-serialization:$ktorVersion
69 | ktorClientAuth = io.ktor:ktor-client-auth:$ktorVersion
70 | ktorClientJetty = io.ktor:ktor-client-jetty:$ktorVersion
71 |
72 | ktorServerServlet = io.ktor:ktor-server-servlet:$ktorVersion
73 | ktorServerNetty = io.ktor:ktor-server-netty:$ktorVersion
74 | ktorServerCore = io.ktor:ktor-server-core:$ktorVersion
75 | ktorLocations = io.ktor:ktor-locations:$ktorVersion
76 | ktorServerSessions = io.ktor:ktor-server-sessions:$ktorVersion
77 | ktorAuth = io.ktor:ktor-auth:$ktorVersion
78 | ktorWebsockets = io.ktor:ktor-websockets:$ktorVersion
79 | ktorSerialization = io.ktor:ktor-serialization:$ktorVersion
80 | logBackClassic = ch.qos.logback:logback-classic:$logbackVersion
81 |
82 | ktorClientJs = io.ktor:ktor-client-js:$ktorVersion
83 | ktorClientJsonJs = io.ktor:ktor-client-json-js:$ktorVersion
84 | ktorClientSerializationJs = io.ktor:ktor-client-serialization-js:$ktorVersion
85 |
86 | # Android
87 |
88 | androidXVersion = 1.1.0
89 |
90 | androidXAppCompat = androidx.appcompat:appcompat:$androidXVersion
91 | androidXCoreKtx = androidx.core:core-ktx:$androidXVersion
92 | androidXFragment = androidx.fragment:fragment-ktx:$androidXVersion
93 | androidXActivity = androidx.activity:activity-ktx:1.0.0
94 | androidXConstraintLayout = androidx.constraintlayout:constraintlayout:1.1.3
95 | glideImageLibrary = com.github.bumptech.glide:glide:3.8.0
96 |
97 | # Testing
98 |
99 | ktorServerTests = io.ktor:ktor-server-tests:$ktorVersion
100 | jUnit = junit:junit:4.12
101 |
102 | #Android Testing
103 | androidXTestRunner = androidx.test:runner:1.2.0
104 | androidXTestEspressoCore = androidx.test.espresso:espresso-core:3.2.0
105 |
106 | ##Android Support
107 | #androidSupportAppCompatV7 = com.android.support:appcompat-v7:28.0.0
108 | #androidSupportConstraintLayout = com.android.support.constraint:constraint-layout:1.1.
109 | #androidSupportTestRunner = com.android.support.test:runner:1.0.2
110 |
111 | #Android TV
112 | androidTvLeanback = androidx.leanback:leanback:1.0.0
113 |
114 | # JavaFX
115 |
116 | javaFxVersion = 12
117 |
118 | javaFxPlugin = org.openjfx:javafx-plugin:$javaFxPluginVersion
119 |
120 | javaFxBase = org.openjfx:javafx-base:$javaFxVersion
121 | javaFxGraphics = org.openjfx:javafx-graphics:$javaFxVersion
122 | javaFxControls = org.openjfx:javafx-controls:$javaFxVersion
123 | javaFxFxml = org.openjfx:javafx-fxml:$javaFxVersion
124 |
125 | tornadoFx = no.tornado:tornadofx:$tornadoFxVersion
126 | jfoenix = com.jfoenix:jfoenix:9.0.10
127 |
128 | # HTML
129 | kotlinxHtmlJs = org.jetbrains.kotlinx:kotlinx-html-js:0.7.2
--------------------------------------------------------------------------------
/Code/shared.settings.gradle.kts:
--------------------------------------------------------------------------------
1 |
2 | // Allow Gradle to follow meta-data to resolve multi-platform artifacts
3 | enableFeaturePreview("GRADLE_METADATA")
4 |
5 | //buildCache {
6 | // local {
7 | // directory = File(rootDir, "build-cache")
8 | // removeUnusedEntriesAfterDays = 30
9 | // }
10 | //}
11 |
12 | // Workaround for: https://youtrack.jetbrains.com/issue/KT-27612
13 | pluginManagement {
14 |
15 | repositories {
16 | gradlePluginPortal()
17 | jcenter()
18 | google()
19 | maven( url = "https://kotlin.bintray.com/kotlinx" )
20 | maven( url = "https://kotlin.bintray.com/kotlin/ktor" )
21 | }
22 |
23 | apply(from = "shared.gradle.kts")
24 |
25 | val androidGradlePlugin : String by extra
26 | val kotlinSerializationPlugin : String by extra
27 | val kotlinGradlePlugin : String by extra
28 | val javaFxPlugin : String by extra
29 | val bintrayGradlePlugin : String by extra
30 |
31 | /**
32 | * Having resolutionStrategy defined here allows plugin ID's nominated in the `plugins {}` block of each
33 | * Gradle sub-project to be mapped to actual Gradle artifacts just once.
34 | */
35 | resolutionStrategy {
36 | eachPlugin {
37 | val module = when(requested.id.id) {
38 | "org.jetbrains.kotlin.jvm",
39 | "org.jetbrains.kotlin.multiplatform",
40 | "kotlin-multiplatform" -> kotlinGradlePlugin
41 | "kotlinx-serialization" -> kotlinSerializationPlugin
42 | "com.android.library" -> androidGradlePlugin
43 | "com.jfrog.bintray" -> bintrayGradlePlugin
44 | else -> return@eachPlugin
45 | }
46 | useModule(module)
47 | }
48 | }
49 | }
50 |
51 | include(":shared")
52 | project(":shared").projectDir = File(buildscript.sourceFile!!.parent,"Shared")
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Chris Hatton
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.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Status
2 |
3 | 
4 | 
5 |
6 |
7 | # Background
8 |
9 | This is aims to be an idiomatic, up-to-date example of a Kotlin Multi-Platform Client/Server Application.
10 |
11 | It is intended both as a learning resource, and as a basis for forking new real-world Application repositories.
12 |
13 | The Server portion is written using JetBrain's [Ktor framework](https://ktor.io/) and builds as a [WAR](https://en.wikipedia.org/wiki/WAR_(file_format)), suitable for hosting by [Jetty](https://www.eclipse.org/jetty/), [TomCat](https://tomcat.apache.org/) or other Java Web-Application container.
14 |
15 | Clients are built for:
16 | * Android
17 | * Mobile / Tablet
18 | * TV
19 | * iOS
20 | * Mobile / Tablet (*Not built by GitLabs CI pipeline for want of an OS-X Runner*)
21 | * JavaFX Desktop
22 |
23 |
--------------------------------------------------------------------------------