Skip to content

Commit

Permalink
1.0.1(#2)
Browse files Browse the repository at this point in the history
* decouple view in HomeView.kt and theme in PoliterAiTheme.kt and remove not used Platform classes from directories.

* remove redundant insetsx dependency

* Add ktor to retrieve data from internet

* encodeURLParameter and fix error on desktop

* upgraded compose-plugin, kotlin and ktorVersion to latest version

* fix not scrolling and not being able to see the bottom content in landscape mode

* make message alignment to center

* suppress warning because it is harmful

* add firebase

* Create compose_ci.yml

* added key.properties to ignored entries

* add codemagic.yaml

* add required oracle distribution for ci/cd

* add required corretto distribution for ci/cd, because oracle does not work

* add required semeru distribution for ci/cd, because corretto does not work

* add required temurin distribution for ci/cd, because other do not work

* change the name of the release file for testing

* Add versionName and applicationId to libs.versions.toml file

* added codemagic.keystore to ignored entries

* Add signing debug and release versions

* added keystores to ignored entries

* Add write key.properties file to CI

* Add write codemagic.keystore file to CI

* fix mistake in github action

* test

* added keystores to ignored entries

* delete keystores from version control

* add write politerai_release.keystore file to github actions

* remove codemagic keystore from github actions

* fix mistake with environment

* add Create keystore folder to github actions

* add Write politerai_debug.keystore file to github actions

* fix oversight in github actions CI

* test

* Add icon

* test

* add screenshots

* Increment version to 1.0.1+2

* Change codemagic.yaml workflow

* add FeatureGraphic.png

* test CI

* test CI

* release

* Add write codemagic.keystore file.

* test

* change signingConfigs for codemagic

* change the name of the AI model

* Update README.md
  • Loading branch information
Turskyi authored Dec 9, 2023
1 parent d8ef362 commit 0a812cf
Show file tree
Hide file tree
Showing 58 changed files with 740 additions and 317 deletions.
63 changes: 63 additions & 0 deletions .github/workflows/compose_ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Upload to Firebase App Distribution

on:
push:
branches:
- dev

jobs:
build:
name: Build Politer AI Android mobile application and upload to Firebase App Distribution
runs-on: ubuntu-latest

steps:
- uses: actions/[email protected]

- name: Set up JDK 17
uses: actions/setup-java@v2
with:
java-version: '17'
distribution: 'temurin' # Eclipse Temurin https://adoptium.net/

- name: Write key.properties file
run: |
echo $KEY_PROPERTIES | base64 -d > key.properties
shell: bash
env:
KEY_PROPERTIES: ${{ secrets.KEY_PROPERTIES }}

- name: Create keystore folder
run: mkdir -p composeApp/src/androidMain/keystore

- name: Write politerai_release.keystore file
env:
RELEASE_KEYSTORE: ${{ secrets.RELEASE_KEYSTORE }}
run: |
echo $RELEASE_KEYSTORE | base64 --decode > composeApp/src/androidMain/keystore/politerai_release.keystore
- name: Write politerai_debug.keystore file
run: |
echo $DEBUG_KEYSTORE | base64 -d > composeApp/src/androidMain/keystore/politerai_debug.keystore
shell: bash
env:
DEBUG_KEYSTORE: ${{ secrets.DEBUG_KEYSTORE }}

- name: Write codemagic.keystore file
run: |
echo $CODEMAGIC_KEYSTORE | base64 -d > composeApp/src/androidMain/keystore/codemagic.keystore
shell: bash
env:
CODEMAGIC_KEYSTORE: ${{ secrets.CODEMAGIC_KEYSTORE }}

- name: Generate Release APK
run: ./gradlew assembleRelease

- name: upload artifact to Firebase App Distribution
uses: wzieba/Firebase-Distribution-Github-Action@v1
with:
appId: ${{secrets.FIREBASE_ANDROID_APP_ID}}
token: ${{secrets.FIREBASE_TOKEN}}
groups: testers
releaseNotes: "Politer AI Android Application Build"
file: composeApp/build/outputs/apk/release/composeApp-release.apk

5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,8 @@ captures
!*.xcodeproj/project.xcworkspace/
!*.xcworkspace/contents.xcworkspacedata
**/xcshareddata/WorkspaceSettings.xcsettings
key.properties
composeApp/src/androidMain/keystore/codemagic.keystore
pc-api-8790223297246728168-552-84bd97eeb74a.json
politerai_debug.keystore
politerai_release.keystore
60 changes: 54 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,70 @@
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner-direct-single.svg)](https://stand-with-ukraine.pp.ua)

# Politer AI

[![Codemagic build status](https://api.codemagic.io/apps/656e850f56b6e401cb0544dc/android-kmm-workflow/status_badge.svg)](https://codemagic.io/apps/656e850f56b6e401cb0544dc/android-kmm-workflow/latest_build)

This is a Kotlin Multiplatform project targeting Android, iOS, Desktop.
**Kotlin Multiplatform** is a broad technology that enables cross-platform development with Kotlin.

## PROJECT SPECIFICATION

• Programming language: [Kotlin](https://kotlinlang.org/);

• SDK: [Android](https://developer.android.com/tools);

• Framework: [Compose Multiplatform](https://www.jetbrains.com/lp/compose-multiplatform/);

• Interface: [Compose](https://developer.android.com/jetpack/compose);

• HTTP client: [Ktor](https://ktor.io);

• Reactive programming: [Coroutines](https://developer.android.com/kotlin/coroutines);

• Version control system: [Git](https://git-scm.com);

• Git Hosting Service: [GitHub](https://github.com);

• CI/CD: [GitHub Actions](https://docs.github.com/en/actions) is used to deliver new Android
Package (APK) to [Firebase App Distribution](https://firebase.google.com/docs/app-distribution)
after every push to the **dev** branch, [Codemagic](https://codemagic.io/start/) is used to deliver
new release app bundle to **Google Play** after every push to **master** branch;

• App testing platforms:
[Firebase App Distribution](https://appdistribution.firebase.dev/i/353f302e0032e469);

• App store:
[Google Play](https://play.google.com/store/apps/details?id=com.turskyi.politerai);

• Operating system: [Android](https://www.android.com/);

• Architectural pattern:
[Monolith](https://learn.microsoft.com/en-us/dotnet/architecture/modern-web-apps-azure/common-web-application-architectures#all-in-one-applications);

### Folder structure

* `/composeApp` is for code that is shared across Compose Multiplatform applications.
It contains several subfolders:
- `commonMain` is for code that’s common for all targets.
- Other folders are for Kotlin code that will be compiled for only the platform indicated in the
folder name.

* `/iosApp` contains iOS applications.

**Kotlin Multiplatform** is a broad technology that enables cross-platform development with Kotlin.
**Compose Multiplatform** is a focused library that enables cross-platform UI development with
Jetpack Compose.

## Credits
**Code Readability:** code is easily readable with no unnecessary blank lines, no unused variables
or methods, and no commented-out code, all variables, methods, and resource IDs are descriptively
named such that another developer reading the code can easily understand their function.

This project is based on the
[Get started with Compose Multiplatform — tutorial](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-multiplatform-getting-started.html)
by [JetBrains](https://github.com/JetBrains).
• Screenshots:

<!--suppress CheckImageSize -->
<img src="screenshots/PixelTablet2023.png" width="800" alt="screenshot of the home page">
<img src="screenshots/PixelXL2023.png" width="200" alt="screenshot">

## Credits

This project is based on the
[Get started with Compose Multiplatform — tutorial](https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-multiplatform-getting-started.html)
by [JetBrains](https://github.com/JetBrains).
7 changes: 7 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
buildscript {
dependencies {
classpath(libs.gradle)
classpath(libs.google.services)
classpath(libs.firebase.crashlytics.gradle)
}
}
plugins {
// this is necessary to avoid the plugins to be loaded multiple times
// in each subproject's classloader
Expand Down
47 changes: 47 additions & 0 deletions codemagic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
workflows:
android-kmm-workflow:
name: Politer AI Android Kotlin multiplatform workflow to publish app bundle to Google Play
max_build_duration: 120
environment:
android_signing:
- keystore_reference
groups:
- google_play_credentials # <-- (Includes GCLOUD_SERVICE_ACCOUNT_CREDENTIALS - google-services.json here)
vars:
PACKAGE_NAME: "com.turskyi.politerai"
triggering:
events:
- push
branch_patterns:
- pattern: master
include: true
source: true
scripts:
- name: Build Android release
script: |
LATEST_GOOGLE_PLAY_BUILD_NUMBER=$(google-play get-latest-build-number --package-name "$PACKAGE_NAME")
if [ -z $LATEST_GOOGLE_PLAY_BUILD_NUMBER ]; then
# fallback in case no build number was found from Google Play.
# Alternatively, you can `exit 1` to fail the build
# BUILD_NUMBER is a Codemagic built-in variable tracking the number
# of times this workflow has been built
UPDATED_BUILD_NUMBER=$BUILD_NUMBER
else
UPDATED_BUILD_NUMBER=$(($LATEST_GOOGLE_PLAY_BUILD_NUMBER + 1))
fi
cd $CM_BUILD_DIR/androidApp
./gradlew bundleRelease \
-PversionCode=$UPDATED_BUILD_NUMBER \
-PversionName=1.0.$UPDATED_BUILD_NUMBER
artifacts:
- composeApp/build/outputs/**/**/*.aab
publishing:
email:
recipients:
- [email protected]
notify:
success: true
failure: true
google_play:
credentials: $GCLOUD_SERVICE_ACCOUNT_CREDENTIALS
track: production
111 changes: 97 additions & 14 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import org.jetbrains.compose.ExperimentalComposeLibrary
import org.jetbrains.compose.desktop.application.dsl.TargetFormat
import java.util.Properties

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidApplication)
alias(libs.plugins.jetbrainsCompose)
id("org.jetbrains.kotlin.android") version "1.9.20" apply false
kotlin("plugin.serialization").version("1.9.21")
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}

val keystorePropertiesFile: File = rootProject.file("key.properties")
val keystoreProperties: Properties = Properties()
keystoreProperties.load(keystorePropertiesFile.inputStream())

kotlin {
androidTarget {
compilations.all {
Expand All @@ -16,9 +24,9 @@ kotlin {
}
}
}

jvm("desktop")

listOf(
iosX64(),
iosArm64(),
Expand All @@ -29,43 +37,107 @@ kotlin {
isStatic = true
}
}

sourceSets {
val desktopMain by getting

desktopMain.dependencies {
implementation(compose.desktop.currentOs)
implementation(libs.ktor.client.cio)
}

androidMain.dependencies {
implementation(libs.compose.ui)
implementation(libs.compose.ui.tooling.preview)
implementation(libs.androidx.activity.compose)
implementation(libs.ktor.client.android)
}
desktopMain.dependencies {
implementation(compose.desktop.currentOs)
}

commonMain.dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
@OptIn(ExperimentalComposeLibrary::class)
implementation(compose.components.resources)
implementation("com.moriatsushi.insetsx:insetsx:0.1.0-alpha10")
implementation(libs.kotlinx.coroutines.core)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.kotlinx.json)
implementation(libs.ktor.client.json)
}
iosMain.dependencies {
implementation(libs.ktor.client.darwin)
}
}
}

android {
namespace = "com.turskyi.politerai"
namespace = libs.versions.applicationId.get()
compileSdk = libs.versions.android.compileSdk.get().toInt()

sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
sourceSets["main"].res.srcDirs("src/androidMain/res")
sourceSets["main"].resources.srcDirs("src/commonMain/resources")

defaultConfig {
applicationId = "com.turskyi.politerai"
applicationId = libs.versions.applicationId.get()
minSdk = libs.versions.android.minSdk.get().toInt()
targetSdk = libs.versions.android.targetSdk.get().toInt()
versionCode = 1
versionName = "1.0"
versionCode = libs.versions.versionCode.get().toInt()
versionName = libs.versions.versionName.get()
}
signingConfigs {
register("release") {
if (System.getenv()["FCI_BUILD_ID"] != null) { // FCI_BUILD_ID is exported by Codemagic
storeFile = System.getenv()["CM_KEYSTORE_PATH"]?.let { file(it) }
storePassword = System.getenv()["CM_KEYSTORE_PASSWORD"]
keyAlias = System.getenv()["CM_KEY_ALIAS"]
keyPassword = System.getenv()["CM_KEY_PASSWORD"]
} else {
storeFile = file(
path = keystoreProperties["storeFile"] as? String
?: throw IllegalStateException("storeFile is missing or invalid"),
)
storePassword = keystoreProperties["storePassword"] as? String
?: throw IllegalStateException("storePassword is missing or invalid")
keyAlias = keystoreProperties["keyAlias"] as? String ?: throw IllegalStateException(
"keyAlias is missing or invalid"
)
keyPassword = keystoreProperties["keyPassword"] as? String
?: throw IllegalStateException("keyPassword is missing or invalid")
}
}
register("dev") {
storeFile = file(
path = keystoreProperties["SIGNING_KEY_DEBUG_PATH"] as? String
?: throw IllegalStateException(
"SIGNING_KEY_DEBUG_PATH for storeFile is missing or invalid",
),
)
storePassword = keystoreProperties["SIGNING_KEY_DEBUG_PASSWORD"] as? String
?: throw IllegalStateException("storePassword is missing or invalid")
keyAlias = keystoreProperties["SIGNING_KEY_DEBUG_KEY"] as? String
?: throw IllegalStateException(
"keyAlias is missing or invalid"
)
keyPassword = keystoreProperties["SIGNING_KEY_DEBUG_KEY_PASSWORD"] as? String
?: throw IllegalStateException("keyPassword is missing or invalid")
}
register("production") {
storeFile = file(
path = keystoreProperties["SIGNING_KEY_RELEASE_PATH"] as? String
?: throw IllegalStateException(
"SIGNING_KEY_RELEASE_PATH for storeFile is missing or invalid",
),
)
storePassword = keystoreProperties["SIGNING_KEY_RELEASE_PASSWORD"] as? String
?: throw IllegalStateException("storePassword is missing or invalid")
keyAlias = keystoreProperties["SIGNING_KEY_RELEASE_KEY"] as? String
?: throw IllegalStateException(
"keyAlias is missing or invalid"
)
keyPassword = keystoreProperties["SIGNING_KEY_RELEASE_KEY_PASSWORD"] as? String
?: throw IllegalStateException("keyPassword is missing or invalid")
}
}
buildFeatures {
compose = true
Expand All @@ -81,6 +153,15 @@ android {
buildTypes {
getByName("release") {
isMinifyEnabled = false
signingConfig =
if (System.getenv()["CI"] == "true") { // CI=true is exported by Codemagic
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("production")
}
}
getByName("debug") {
signingConfig = signingConfigs.getByName("dev")
}
}
compileOptions {
Expand All @@ -94,6 +175,8 @@ android {
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.core)
implementation(libs.firebase.crashlytics)
implementation(libs.firebase.analytics)
}

compose.desktop {
Expand All @@ -102,8 +185,8 @@ compose.desktop {

nativeDistributions {
targetFormats(TargetFormat.Dmg, TargetFormat.Msi, TargetFormat.Deb)
packageName = "com.turskyi.politerai"
packageVersion = "1.0.0"
packageName = libs.versions.applicationId.get()
packageVersion = libs.versions.versionName.get()
}
}
}
Loading

0 comments on commit 0a812cf

Please sign in to comment.