diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 94f3051..f02281a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,8 +1,8 @@ -name: SonarCloud +name: SonarQube on: push: branches: - - master + - main pull_request: types: [opened, synchronize, reopened] jobs: @@ -10,28 +10,27 @@ jobs: name: Build and analyze runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: 'zulu' # Alternative distribution options are available - - name: Cache SonarCloud packages - uses: actions/cache@v3 + - name: Cache SonarQube packages + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Gradle packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - name: Build and analyze env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: ./gradlew build sonar --info \ No newline at end of file diff --git a/.idea/compiler.xml b/.idea/compiler.xml index b589d56..b86273d 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,6 @@ - + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 0897082..639c779 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -4,6 +4,7 @@ diff --git a/.idea/misc.xml b/.idea/misc.xml index 8978d23..b2c751a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,6 +1,6 @@ - + diff --git a/.idea/vcs.xml b/.idea/vcs.xml index 288b36b..35eb1dd 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -1,7 +1,6 @@ - - + \ No newline at end of file diff --git a/README.md b/README.md index 0d16f77..985cd6e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # GitHub CI-SonarCloud Erklärung ->:warning: Eine funktionierende CI mit den Konfigurationen unten beschrieben kann in diesem Repository gefunden werden :warning: +>:warning: Eine funktionierende CI für ein Gradle Android Kotlin Projekt mit den unten beschriebenen Konfigurationen für Software Engineering II kann in diesem Repository gefunden werden. :warning: ## Account Einrichtungen und erste Projekterstellungen Kurze Erklärungsschritte für zukünftige CIs in diese Richtung. Zum Ausgeben der Metriken wird Sonarcloud verwendet @@ -19,19 +19,19 @@ Kurze Erklärungsschritte für zukünftige CIs in diese Richtung. Zum Ausgeben d ## Gradle Project Änderungen - **Projekt-Spezifikationen**: - - **Gradle Version** 8.0 - - **Android Gradle Plugin Version** 8.3.0 - - **SDK Version (target)** 34 - - **SDK Version (min)** 29 - - **Groovy DSL** + - **Gradle Version** 8.11.1 + - **Android Gradle Plugin Version (agp)** 8.9.0 + - **SDK Version (target)** 35 + - **SDK Version (min)** 30 + - **Kotlin DSL** - Im Hauptordner wird ein **.github/workflows** Ordner hinzugefügt - In diesen wird eine **build.yml** Datei erstellt. Diese kann via ``Administration -> Analysis Method -> Github Actions -> Gradle -> build.yml`` kopiert werden: ```yml name: SonarCloud -name: SonarCloud +name: SonarQube on: push: branches: - - master # CHECK IF MAIN BRANCH NAME IS CORRECT + - main # CHECK YOUR BRANCH NAME pull_request: types: [opened, synchronize, reopened] jobs: @@ -39,104 +39,145 @@ jobs: name: Build and analyze runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: 'zulu' # Alternative distribution options are available - - name: Cache SonarCloud packages - uses: actions/cache@v3 + - name: Cache SonarQube packages + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Gradle packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.gradle/caches key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} restore-keys: ${{ runner.os }}-gradle - name: Build and analyze env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} run: ./gradlew build sonar --info ``` **Hinweis**: Auf den korrekten **Branch-Namen** muss geachtet werden -- Weiters muss die **app/build.gradle** Datei erweitert werden. Da diese (hier in SE2) ebenso um Jacoco erweitert wird, muss dies ebenfalls noch beachtet werden +- Weiters muss die **app/build.gradle.kts** Datei erweitert werden. Da diese (hier in SE2) ebenso um Jacoco erweitert wird, muss dies ebenfalls noch beachtet werden - Im Folgenden File werden die Änderungen mit Kommentaren markiert ```gradle plugins { - alias(libs.plugins.androidApplication) - // --Beide ids hinzufügen-- Auf sonarqube Version achten (Siehe Sonarcloud -> Gradle) - id 'jacoco' - id 'org.sonarqube' version '4.4.1.3373' + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + // --Beide ids hinzufügen-- Auf sonarqube Version achten (6.X) ist derzeit nicht kompatibel! + id("jacoco") + id("org.sonarqube") version "5.1.0.4882" } android { // Werte müssen mit diesen aus der eigenen App übernommen werden - namespace 'net.jamnig.testapp' - compileSdk 34 + namespace = "net.jamnig.testapp" + compileSdk = 35 defaultConfig { - applicationId "net.jamnig.testapp" - minSdk 29 - targetSdk 34 - versionCode 1 - versionName "1.0" + applicationId = "net.jamnig.testapp" + minSdk = 30 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) } } + compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true } // --Hinzufügen-- testOptions { - unitTests.all { - useJUnitPlatform() - finalizedBy jacocoTestReport + unitTests { + all { + it.useJUnitPlatform() + it.finalizedBy(tasks.named("jacocoTestReport")) + } } } } + // --Hinzufügen-- + Überprüfen, ob xml.destination Path korrekt ist -tasks.register('jacocoTestReport', JacocoReport) { - dependsOn 'testDebugUnitTest' +tasks.register("jacocoTestReport") { + dependsOn("testDebugUnitTest") reports { - xml.required = true - xml.destination file("${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml") + xml.required.set(true) + xml.outputLocation.set(file("${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")) } - def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] - def debugTree = fileTree(dir: "${project.layout.buildDirectory.get().asFile}/intermediates/javac/debug", excludes: fileFilter) - def mainSrc = "${project.projectDir}/src/main/java" + val fileFilter = listOf( + "**/R.class", + "**/R$*.class", + "**/BuildConfig.*", + "**/Manifest*.*", + "**/*Test*.*", + "android/**/*.*" + ) - sourceDirectories.from = files([mainSrc]) - classDirectories.from = files([debugTree]) - executionData.from = files("${project.layout.buildDirectory.get().asFile}/jacoco/testDebugUnitTest.exec") + val debugTree = + fileTree("${project.layout.buildDirectory.get().asFile}/tmp/kotlin-classes/debug") { + exclude(fileFilter) + } + + val javaDebugTree = + fileTree("${project.layout.buildDirectory.get().asFile}/intermediates/javac/debug") { + exclude(fileFilter) + } + + val mainSrc = listOf( + "${project.projectDir}/src/main/java", + "${project.projectDir}/src/main/kotlin" + ) + + sourceDirectories.setFrom(files(mainSrc)) + classDirectories.setFrom(files(debugTree, javaDebugTree)) + executionData.setFrom(fileTree(project.layout.buildDirectory.get().asFile) { + include("jacoco/testDebugUnitTest.exec") + include("outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec") + }) } // Sonarqube-Werte müssen von Sonarcloud unter Gradle kopiert werden. Diese sind individuell -// --Hinweis-- Darauf achten, dass Jacoco mitkopiert wird +// --Hinweis-- Darauf achten, dass Jacoco ebenfalls hinzugefügt wird sonar { properties { - property "sonar.projectKey", "uni-aau_github-ci" - property "sonar.organization", "uni-aau" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.java.coveragePlugin", "jacoco" - property "sonar.coverage.jacoco.xmlReportPaths", "${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" + property("sonar.projectKey", "uni-aau_github-ci") + property("sonar.organization", "uni-aau") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.java.coveragePlugin", "jacoco") + property( + "sonar.coverage.jacoco.xmlReportPaths", + "${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" + ) } } @@ -145,15 +186,23 @@ sonar { // Dependency-Versionen sind unter **gradle/libs.version.toml** // --Hinweis-- Mit JUnit 5 wird gearbeitet (für jacoco) dependencies { - implementation libs.activity - implementation libs.appcompat - implementation libs.material - implementation libs.constraintlayout - testImplementation libs.junit - testImplementation libs.junit.jupiter.api - testRuntimeOnly libs.junit.jupiter.engine - androidTestImplementation libs.ext.junit - androidTestImplementation libs.espresso.core + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + testImplementation(libs.junit.jupiter.api) + testRuntimeOnly(libs.junit.jupiter.engine) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) } ``` Nun kann die CI entweder mittels **GitHub CI** bei jedem Commit getriggered werden (Ist im Repository unter Actions) oder per Konsole mit dem Befehl **./gradlew build sonar --info** @@ -161,17 +210,17 @@ Nun kann die CI entweder mittels **GitHub CI** bei jedem Commit getriggered werd **WICHTIG:** Da die App mit einer leeren Aktivität mit Android Studio erstellt wurde, wird automatisch ein Testfall hinzugefügt: >**Android:** Unter ``app/src/test/.../ExampleUnitTest.java`` muss dieser (gemeinsam mit @RunWith) **entfernt** werden, da der Testfall noch mit JUnit 4 läuft. JUnit 5 hat anderen Import (``org.junit.jupiter.api.*``). -## Maven Project Änderungen +## Maven Java Spring Boot Project Änderungen - **Projekt-Spezifikationen**: - **Java Version** 17 - Im Hauptordner wird ein **.github/workflows** Ordner hinzugefügt - In diesen wird eine **build.yml** Datei erstellt. Diese kann via ``Administration -> Analysis Method -> Github Actions -> Maven -> build.yml`` kopiert werden: ```yml name: SonarCloud -name: SonarCloud +name: SonarQube on: push: branches: - - main # CHECK IF MAIN BRANCH NAME IS CORRECT + - main pull_request: types: [opened, synchronize, reopened] jobs: @@ -179,35 +228,35 @@ jobs: name: Build and analyze runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis - name: Set up JDK 17 - uses: actions/setup-java@v3 + uses: actions/setup-java@v4 with: java-version: 17 distribution: 'zulu' # Alternative distribution options are available. - - name: Cache SonarCloud packages - uses: actions/cache@v3 + - name: Cache SonarQube packages + uses: actions/cache@v4 with: path: ~/.sonar/cache key: ${{ runner.os }}-sonar restore-keys: ${{ runner.os }}-sonar - name: Cache Maven packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 - name: Build and analyze env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} - run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=AAU-SE2_WebSocketDemo-Server + run: mvn -B verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar -Dsonar.projectKey=SE-II-group-new_testing-4 ``` **Hinweis**: Auf den korrekten **Branch-Namen** muss geachtet werden - Weiters muss die **pom.xml** Datei erweitert werden. - Die pom.xml entspricht einer (via IntelliJ) neu generierten pom.xml mit **Jacoco & SonarCloud** Ergänzungen, sowie die zusätzlichen Änderungen für den Software-Engineering II Server: + ```xml net.jamnig server 1.0-SNAPSHOT + Demo + Demo Server 17 @@ -241,36 +292,32 @@ jobs: - - - - org.junit.jupiter - junit-jupiter-api - 5.10.2 - test - - - - - org.junit.jupiter - junit-jupiter-engine - 5.10.2 - test - - + + + + + org.junit + junit-bom + 5.12.1 + pom + import + + + + org.springframework.boot spring-boot-starter-websocket - 3.2.3 + 3.4.3 org.springframework.boot spring-boot-starter-test - 3.2.3 + 3.4.3 test @@ -278,17 +325,37 @@ jobs: org.projectlombok lombok - 1.18.30 + 1.18.36 provided + + + org.junit.jupiter + junit-jupiter-api + test + + + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + org.springframework.boot + spring-boot-maven-plugin + org.jacoco jacoco-maven-plugin - 0.8.11 + 0.8.12 @@ -304,12 +371,6 @@ jobs: - - - - org.springframework.boot - spring-boot-maven-plugin - diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index d287568..0000000 --- a/app/build.gradle +++ /dev/null @@ -1,77 +0,0 @@ -plugins { - alias(libs.plugins.androidApplication) - id 'jacoco' - id "org.sonarqube" version "4.4.1.3373" -} - -android { - namespace 'net.jamnig.testapp' - compileSdk 34 - - defaultConfig { - applicationId "net.jamnig.testapp" - minSdk 29 - targetSdk 34 - versionCode 1 - versionName "1.0" - - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - } - - buildTypes { - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' - } - } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - testOptions { - unitTests.all { - useJUnitPlatform() - finalizedBy jacocoTestReport - } - } -} - -tasks.register('jacocoTestReport', JacocoReport) { - dependsOn 'testDebugUnitTest' - - reports { - xml.required = true - xml.destination file("${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml") - } - - def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*'] - def debugTree = fileTree(dir: "${project.layout.buildDirectory.get().asFile}/intermediates/javac/debug", excludes: fileFilter) - def mainSrc = "${project.projectDir}/src/main/java" - - sourceDirectories.from = files([mainSrc]) - classDirectories.from = files([debugTree]) - executionData.from = files("${project.layout.buildDirectory.get().asFile}/jacoco/testDebugUnitTest.exec") -} - -sonar { - properties { - property "sonar.projectKey", "uni-aau_github-ci" - property "sonar.organization", "uni-aau" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.java.coveragePlugin", "jacoco" - property "sonar.coverage.jacoco.xmlReportPaths", "${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" - } -} - -dependencies { - implementation libs.activity - implementation libs.appcompat - implementation libs.material - implementation libs.constraintlayout - testImplementation libs.junit - testImplementation libs.junit.jupiter.api - testRuntimeOnly libs.junit.jupiter.engine - androidTestImplementation libs.ext.junit - androidTestImplementation libs.espresso.core -} \ No newline at end of file diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 0000000..dc142a8 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,123 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) + id("jacoco") + id("org.sonarqube") version "5.1.0.4882" +} + +android { + namespace = "net.jamnig.testapp" + compileSdk = 35 + + defaultConfig { + applicationId = "net.jamnig.testapp" + minSdk = 30 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + kotlinOptions { + jvmTarget = "11" + } + buildFeatures { + compose = true + } + testOptions { + unitTests { + all { + it.useJUnitPlatform() + it.finalizedBy(tasks.named("jacocoTestReport")) + } + } + } +} + +tasks.register("jacocoTestReport") { + dependsOn("testDebugUnitTest") + + reports { + xml.required.set(true) + xml.outputLocation.set(file("${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml")) + } + + val fileFilter = listOf( + "**/R.class", + "**/R$*.class", + "**/BuildConfig.*", + "**/Manifest*.*", + "**/*Test*.*", + "android/**/*.*" + ) + + val debugTree = + fileTree("${project.layout.buildDirectory.get().asFile}/tmp/kotlin-classes/debug") { + exclude(fileFilter) + } + + val javaDebugTree = + fileTree("${project.layout.buildDirectory.get().asFile}/intermediates/javac/debug") { + exclude(fileFilter) + } + + val mainSrc = listOf( + "${project.projectDir}/src/main/java", + "${project.projectDir}/src/main/kotlin" + ) + + sourceDirectories.setFrom(files(mainSrc)) + classDirectories.setFrom(files(debugTree, javaDebugTree)) + executionData.setFrom(fileTree(project.layout.buildDirectory.get().asFile) { + include("jacoco/testDebugUnitTest.exec") + include("outputs/unit_test_code_coverage/debugUnitTest/testDebugUnitTest.exec") + }) +} + +sonar { + properties { + property("sonar.projectKey", "uni-aau_github-ci") + property("sonar.organization", "uni-aau") + property("sonar.host.url", "https://sonarcloud.io") + property("sonar.java.coveragePlugin", "jacoco") + property( + "sonar.coverage.jacoco.xmlReportPaths", + "${project.projectDir}/build/reports/jacoco/jacocoTestReport/jacocoTestReport.xml" + ) + } +} + +dependencies { + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + testImplementation(libs.junit) + testImplementation(libs.junit.jupiter.api) + testRuntimeOnly(libs.junit.jupiter.engine) + androidTestImplementation(libs.androidx.junit) + androidTestImplementation(libs.androidx.espresso.core) + androidTestImplementation(platform(libs.androidx.compose.bom)) + androidTestImplementation(libs.androidx.ui.test.junit4) + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) +} \ No newline at end of file diff --git a/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.java b/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.java deleted file mode 100644 index 87d8e8f..0000000 --- a/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.java +++ /dev/null @@ -1,26 +0,0 @@ -package net.jamnig.testapp; - -import android.content.Context; - -import androidx.test.platform.app.InstrumentationRegistry; -import androidx.test.ext.junit.runners.AndroidJUnit4; - -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.junit.Assert.*; - -/** - * Instrumented test, which will execute on an Android device. - * - * @see Testing documentation - */ -//@RunWith(AndroidJUnit4.class) -public class ExampleInstrumentedTest { - @Test - public void useAppContext() { - // Context of the app under test. - Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); - assertEquals("net.jamnig.testapp", appContext.getPackageName()); - } -} \ No newline at end of file diff --git a/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.kt b/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.kt new file mode 100644 index 0000000..f16a0df --- /dev/null +++ b/app/src/androidTest/java/net/jamnig/testapp/ExampleInstrumentedTest.kt @@ -0,0 +1,20 @@ +package net.jamnig.testapp + +import androidx.test.platform.app.InstrumentationRegistry +import org.junit.Assert.assertEquals +import org.junit.Test + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +//@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("net.jamnig.testapp", appContext.packageName) + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a042090..c565e5f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -14,7 +14,9 @@ tools:targetApi="31"> + android:exported="true" + android:label="@string/app_name" + android:theme="@style/Theme.TestApp"> diff --git a/app/src/main/java/net/jamnig/testapp/Coverage.kt b/app/src/main/java/net/jamnig/testapp/Coverage.kt new file mode 100644 index 0000000..9f0a10f --- /dev/null +++ b/app/src/main/java/net/jamnig/testapp/Coverage.kt @@ -0,0 +1,7 @@ +package net.jamnig.testapp + +class Coverage { + fun add(a: Int, b: Int): Int { + return a + b + } +} \ No newline at end of file diff --git a/app/src/main/java/net/jamnig/testapp/MainActivity.java b/app/src/main/java/net/jamnig/testapp/MainActivity.java deleted file mode 100644 index 2ddf583..0000000 --- a/app/src/main/java/net/jamnig/testapp/MainActivity.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.jamnig.testapp; - -import androidx.appcompat.app.AppCompatActivity; - -import android.os.Bundle; -import android.util.Log; - -public class MainActivity extends AppCompatActivity { - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Log.d("TAG", "Hello World!"); - } -} \ No newline at end of file diff --git a/app/src/main/java/net/jamnig/testapp/MainActivity.kt b/app/src/main/java/net/jamnig/testapp/MainActivity.kt new file mode 100644 index 0000000..7542ece --- /dev/null +++ b/app/src/main/java/net/jamnig/testapp/MainActivity.kt @@ -0,0 +1,47 @@ +package net.jamnig.testapp + +import android.os.Bundle +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.tooling.preview.Preview +import net.jamnig.testapp.ui.theme.TestAppTheme + +class MainActivity : ComponentActivity() { + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + enableEdgeToEdge() + setContent { + TestAppTheme { + Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> + Greeting( + name = "Android", + modifier = Modifier.padding(innerPadding) + ) + } + } + } + } +} + +@Composable +fun Greeting(name: String, modifier: Modifier = Modifier) { + Text( + text = "Hello $name!", + modifier = modifier + ) +} + +@Preview(showBackground = true) +@Composable +fun GreetingPreview() { + TestAppTheme { + Greeting("Android") + } +} \ No newline at end of file diff --git a/app/src/main/java/net/jamnig/testapp/ui/theme/Color.kt b/app/src/main/java/net/jamnig/testapp/ui/theme/Color.kt new file mode 100644 index 0000000..7ad0a7e --- /dev/null +++ b/app/src/main/java/net/jamnig/testapp/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package net.jamnig.testapp.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) \ No newline at end of file diff --git a/app/src/main/java/net/jamnig/testapp/ui/theme/Theme.kt b/app/src/main/java/net/jamnig/testapp/ui/theme/Theme.kt new file mode 100644 index 0000000..cc08215 --- /dev/null +++ b/app/src/main/java/net/jamnig/testapp/ui/theme/Theme.kt @@ -0,0 +1,58 @@ +package net.jamnig.testapp.ui.theme + +import android.app.Activity +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun TestAppTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} \ No newline at end of file diff --git a/app/src/main/java/net/jamnig/testapp/ui/theme/Type.kt b/app/src/main/java/net/jamnig/testapp/ui/theme/Type.kt new file mode 100644 index 0000000..8d2cd0f --- /dev/null +++ b/app/src/main/java/net/jamnig/testapp/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package net.jamnig.testapp.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml deleted file mode 100644 index 895f007..0000000 --- a/app/src/main/res/layout/activity_main.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml deleted file mode 100644 index 43bf1ff..0000000 --- a/app/src/main/res/values-night/themes.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - \ No newline at end of file diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml index 0c7ca4f..2814b87 100644 --- a/app/src/main/res/values/themes.xml +++ b/app/src/main/res/values/themes.xml @@ -1,16 +1,5 @@ - - - + + + +