Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate genres list to Compose #159

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ max_line_length=off
ktlint_standard_property-naming=disabled
ktlint_standard_filename=disabled
ktlint_standard_package-name=disabled
ktlint_code_style=android_studio
ktlint_code_style=android_studio
ktlint_standard_trailing-comma-on-declaration-site=disabled
ktlint_standard_trailing-comma-on-call-site=disabled
ktlint_function_naming_ignore_when_annotated_with=Composable
52 changes: 50 additions & 2 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ plugins {
}

android {
val fragment_version = "1.6.2"
val mockk_version = "1.13.11"

compileSdk = 34

Expand Down Expand Up @@ -85,6 +87,14 @@ android {
}
namespace = "com.simplecityapps.shuttle"

buildFeatures {
compose = true
}

composeOptions {
kotlinCompilerExtensionVersion = rootProject.extra["compose_version"] as String
}

dependencies {
implementation(fileTree("dir" to "libs", "include" to listOf("*.jar")))

Expand Down Expand Up @@ -123,9 +133,36 @@ android {
// RecyclerView FastScroll
implementation("com.github.timusus:RecyclerView-FastScroll:dev-SNAPSHOT")

// FastScroller for Compose Multiplatform
implementation("io.github.oikvpqya.compose.fastscroller:fastscroller-core:0.2.0")
implementation("io.github.oikvpqya.compose.fastscroller:fastscroller-material3:0.2.0")
implementation("io.github.oikvpqya.compose.fastscroller:fastscroller-indicator:0.2.0")

// AppCompat
implementation("androidx.appcompat:appcompat:1.6.1")

val composeBom = platform("androidx.compose:compose-bom:2023.10.01")

implementation(composeBom)
androidTestImplementation(composeBom)
testImplementation(composeBom)

// Material Design 3
implementation("androidx.compose.material3:material3")

// Android Studio Preview support
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")

// UI Tests
androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-test-manifest")

// Optional - Integration with activities
implementation("androidx.activity:activity-compose:1.6.1")
// Optional - Integration with LiveData
implementation("androidx.compose.runtime:runtime-livedata")

// Material
implementation("com.google.android.material:material:1.10.0")

Expand Down Expand Up @@ -154,7 +191,7 @@ android {
implementation("androidx.viewpager2:viewpager2:1.1.0-beta02")

// ViewPager Circle Indicator
implementation("me.relex:circleindicator:2.1.4")
implementation("me.relex:circleindicator:2.1.6")

// AndroidX Media
implementation("androidx.media:media:1.6.0")
Expand Down Expand Up @@ -190,7 +227,7 @@ android {
implementation("androidx.drawerlayout:drawerlayout:1.2.0")

// New fragment manager
implementation("androidx.fragment:fragment-ktx:1.6.2")
implementation("androidx.fragment:fragment-ktx:$fragment_version")

// Glide
implementation("com.github.bumptech.glide:glide:4.16.0")
Expand Down Expand Up @@ -230,6 +267,11 @@ android {
androidTestImplementation("androidx.test:rules:1.5.0")
androidTestImplementation("androidx.test:core-ktx:1.5.0")
androidTestImplementation("org.hamcrest:hamcrest-library:1.3")
implementation("androidx.test.ext:junit-ktx:1.1.5")
debugImplementation("androidx.fragment:fragment-testing:$fragment_version")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
androidTestImplementation("io.mockk:mockk-android:${mockk_version}")
androidTestImplementation("io.mockk:mockk-agent:${mockk_version}")

// Remote config
implementation(project(":android:remote-config"))
Expand All @@ -246,6 +288,12 @@ android {
buildFeatures.buildConfig = true
}

androidComponents {
onVariants(selector().withBuildType("release")) {
it.packaging.resources.excludes.add("META-INF/**")
}
}

apply(plugin = "com.google.gms.google-services")

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package com.simplecityapps.shuttle.ui.screens.library.genres

import android.content.ComponentName
import android.content.Intent
import android.os.Bundle
import androidx.annotation.StyleRes
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.core.util.Preconditions
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation.findNavController
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.matcher.ViewMatchers.withText
import com.simplecityapps.shuttle.HiltTestActivity
import com.simplecityapps.shuttle.R
import com.simplecityapps.shuttle.ui.MainActivity
import dagger.hilt.android.testing.HiltAndroidRule
import dagger.hilt.android.testing.HiltAndroidTest
import io.mockk.MockKAnnotations
import io.mockk.impl.annotations.MockK
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain

@HiltAndroidTest
class GenreListFragmentTest {
@MockK(relaxed = true)
lateinit var viewModel: GenreListViewModel

private val hiltRule = HiltAndroidRule(this)

private val composeTestRule = createAndroidComposeRule<MainActivity>()

@get:Rule
val rule: RuleChain = RuleChain
.outerRule(hiltRule)
.around(composeTestRule)

@get:Rule
val composeTestRule2 = createComposeRule()

@Before
fun goToNonOrganizerFragment() {
MockKAnnotations.init(this)
hiltRule.inject()
launchFragmentInHiltContainer<GenreListFragment>()

composeTestRule.activityRule.scenario.onActivity {
// FIXME: I guess there's a better way to do this
it.preferenceManager.hasSeenThankYouDialog = true
it.preferenceManager.showChangelogOnLaunch = false

findNavController(it, R.id.onboardingNavHostFragment)
.navigate(R.id.mainFragment)
}
}

@Test
fun testEventFragment2() {
onView(withText("Genres")).perform(click())
composeTestRule.onNodeWithTag("genres-list-lazy-column")
.assertIsDisplayed()
}
}

/**
* launchFragmentInContainer from the androidx.fragment:fragment-testing library
* is NOT possible to use right now as it uses a hardcoded Activity under the hood
* (i.e. [EmptyFragmentActivity]) which is not annotated with @AndroidEntryPoint.
*
* As a workaround, use this function that is equivalent. It requires you to add
* [HiltTestActivity] in the debug folder and include it in the debug
* AndroidManifest.xml file as can be found in this project.
*
* See https://developer.android.com/training/dependency-injection/hilt-testing#launchfragment
*/
inline fun <reified T : Fragment> launchFragmentInHiltContainer(
fragmentArgs: Bundle? = null,
@StyleRes themeResId: Int = R.style.AppTheme_Light,
crossinline action: Fragment.() -> Unit = {},
) {
val startActivityIntent = Intent.makeMainActivity(
ComponentName(
ApplicationProvider.getApplicationContext(),
HiltTestActivity::class.java,
)
).putExtra(
"androidx.fragment.app.testing.FragmentScenario.EmptyFragmentActivity.THEME_EXTRAS_BUNDLE_KEY",
themeResId,
)

ActivityScenario
.launch<HiltTestActivity>(startActivityIntent)
.onActivity { activity ->
val fragment = activity.supportFragmentManager.fragmentFactory.instantiate(
Preconditions.checkNotNull(T::class.java.classLoader),
T::class.java.name,
)
fragment.arguments = fragmentArgs
activity.supportFragmentManager.beginTransaction()
}
}
25 changes: 25 additions & 0 deletions android/app/src/debug/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2022 The Android Open Source Project

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.simplecityapps.shuttle">

<application>
<activity
android:name=".HiltTestActivity"
android:exported="false" />
</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.simplecityapps.shuttle

import androidx.appcompat.app.AppCompatActivity
import dagger.hilt.android.AndroidEntryPoint

@AndroidEntryPoint
class HiltTestActivity : AppCompatActivity()
Loading
Loading