Skip to content

Commit 4d21fa4

Browse files
chrisbanesJolandaVerhoefnickbutcherflorina-muntenescuJoseAlcerreca
authored
[All] Update to Compose 1.0.0-alpha06 (android#261)
* [Jetsnack] Cart implementation * [Jetsnack] Reuse Quantity Selector * [Jetsnack] Reuse Destination Bar * [Jetsnack] Add Inspired By Section to Cart * [Jetsnack] Add Checkout Bar to cart * [Jetsnack] Fix Spotless issues * [Jetsnack] Fix review comments * [Jetsnack] Fix review comments * Update to snapshot 6922857. * [Jetsurvey] Bump to alpha06 * [Owl] Update to snapshot 6922857. * [JetChat] Update to snapshot 6922857 * [Rally] Update to snapshot 6922857 * [Jetcaster] Update to snapshot 6922857. * Removes unncessary elevation param * [Crane] Update to 6922857 snapshot (android#246) * [Owl] Replace elevation overlay workaround with AmbientElevationOverlay. * [Jetchat] Replace elevation overlay workaround with AmbientElevationOverlay * [Jetsurvey] Redesigned next/prev buttons * [Jetsurvey] Redesigned progress indicator * [Jetsurvey] Adding elevation to the action bar * [Jetsurvey] Capitalising strings * [Jetsurvey] Question title redesigned * [Jetsurvey] Removing unused composable * [Jetsurvey] Removing the column usage in progress indicator * [Crane] Adds Hilt to the project (android#237) * [JetNews] bump to alpha06 (android#258) * [JetNews] bump to alpha06 * Fix unused modifier on BookmarkButton * Update all samples to AGP 4.2.0-alpha15 * Turn on allWarningsAsErrors in Jetsurvey * Tidy up gradle.properties We now have parallel compilation, caching and on-demand configuration enabled on all projects * Disable Jetifier where possible Only Crane requires Jetifier becuase it uses the Google Maps SDK. * Update all projects to ktlint 0.39.0 * Update snapshot URL * Update to Compose 1.0.0-alpha06 Co-authored-by: Jolanda Verhoef <[email protected]> Co-authored-by: Nick Butcher <[email protected]> Co-authored-by: Nick Butcher <[email protected]> Co-authored-by: Florina Muntenescu <[email protected]> Co-authored-by: Jose Alcerreca <[email protected]> Co-authored-by: Jolanda Verhoef <[email protected]> Co-authored-by: Jose Alcérreca <[email protected]> Co-authored-by: Florina Muntenescu <[email protected]> Co-authored-by: Manuel Vivo <[email protected]> Co-authored-by: Sean McQuillan <[email protected]>
1 parent 4ffcd3b commit 4d21fa4

File tree

124 files changed

+1910
-830
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

124 files changed

+1910
-830
lines changed

.github/ci-gradle.properties

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
/*
2-
* Copyright 2019 Google, Inc.
3-
*
4-
* Licensed under the Apache License, Version 2.0 (the "License");
5-
* you may not use this file except in compliance with the License.
6-
* You may obtain a copy of the License at
7-
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
9-
*
10-
* Unless required by applicable law or agreed to in writing, software
11-
* distributed under the License is distributed on an "AS IS" BASIS,
12-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13-
* See the License for the specific language governing permissions and
14-
* limitations under the License.
15-
*/
1+
#
2+
# Copyright 2020 The Android Open Source Project
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
1616

17-
org.gradle.daemon=false
18-
org.gradle.parallel=true
19-
org.gradle.jvmargs=-Xmx5120m
20-
org.gradle.workers.max=2
17+
org.gradle.daemon=false
18+
org.gradle.parallel=true
19+
org.gradle.jvmargs=-Xmx5120m
20+
org.gradle.workers.max=2
2121

22-
kotlin.incremental=false
23-
kotlin.compiler.execution.strategy=in-process
22+
kotlin.incremental=false
23+
kotlin.compiler.execution.strategy=in-process

Crane/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,38 @@ implemented using a different Activity will be displayed. In there, you can see
3232
embedded in Compose and Compose buttons updating the Android View. Notice how you can also
3333
interact with the `MapView` seamlessly.
3434

35+
## Hilt
36+
37+
Crane uses [Hilt][hilt] to manage its dependencies. The Hilt's ViewModel extension (with the
38+
`@ViewModelInject` annotation) works perfectly with Compose's ViewModel integration (`viewModel()`
39+
composable function) as you can see in the following snippet of code. `viewModel()` will
40+
automatically use the factory that Hilt creates for the ViewModel:
41+
42+
```
43+
class MainViewModel @ViewModelInject constructor(
44+
private val destinationsRepository: DestinationsRepository,
45+
@DefaultDispatcher private val defaultDispatcher: CoroutineDispatcher,
46+
datesRepository: DatesRepository
47+
) : ViewModel() { ... }
48+
49+
@Composable
50+
fun CraneHomeContent(...) {
51+
val viewModel: MainViewModel = viewModel()
52+
...
53+
}
54+
```
55+
56+
Disclaimer: Passing dependencies to a ViewModel which are not available at compile time (which is
57+
sometimes called _assisted injection_) doesn't work as you might expect using `viewModel()`.
58+
Compose's ViewModel integration cannot currently scope a ViewModel to a given composable. Instead
59+
it is always scoped to the host Activity or Fragment. This means that calling `viewModel()` with
60+
different factories in the same host Activity/Fragment don't have the desired effect; the _first_
61+
factory will be always used.
62+
63+
This is the case of the [DetailsViewModel](detailsViewModel), which takes the name of
64+
a `City` as a parameter to load the required information for the screen. However, the above isn't a
65+
problem in this sample, since `DetailsScreen` is always used in it's own newly launched Activity.
66+
3567
## Google Maps SDK
3668

3769
To get the MapView working, you need to get an API key as
@@ -79,6 +111,8 @@ limitations under the License.
79111
[details]: app/src/main/java/androidx/compose/samples/crane/details/DetailsActivity.kt
80112
[data]: app/src/main/java/androidx/compose/samples/crane/data/CraneData.kt
81113
[mainViewModel]: app/src/main/java/androidx/compose/samples/crane/home/MainViewModel.kt
114+
[detailsViewModel]: app/src/main/java/androidx/compose/samples/crane/details/DetailsViewModel.kt
82115
[homeTest]: app/src/androidTest/java/androidx/compose/samples/crane/home/HomeTest.kt
83116
[detailsTest]: app/src/androidTest/java/androidx/compose/samples/crane/details/DetailsActivityTest.kt
84117
[coil-accompanist]: https://github.com/chrisbanes/accompanist
118+
[hilt]: https://d.android.com/hilt

Crane/app/build.gradle

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import com.example.crane.buildsrc.Libs
1919
plugins {
2020
id 'com.android.application'
2121
id 'kotlin-android'
22+
id 'kotlin-kapt'
23+
id 'dagger.hilt.android.plugin'
2224
}
2325

2426
// Reads the Google maps key that is used in the AndroidManifest
@@ -36,7 +38,13 @@ android {
3638
versionCode 1
3739
versionName "1.0"
3840
vectorDrawables.useSupportLibrary = true
39-
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
41+
testInstrumentationRunner "androidx.compose.samples.crane.CustomTestRunner"
42+
43+
javaCompileOptions {
44+
annotationProcessorOptions {
45+
arguments["dagger.hilt.disableModulesHaveInstallInCheck"] = "true"
46+
}
47+
}
4048

4149
manifestPlaceholders = [ googleMapsKey : properties.getProperty("google.maps.key", "") ]
4250
}
@@ -81,14 +89,22 @@ android {
8189
resValues false
8290
shaders false
8391
}
92+
8493
composeOptions {
8594
kotlinCompilerVersion Libs.Kotlin.version
8695
kotlinCompilerExtensionVersion Libs.AndroidX.Compose.version
8796
}
97+
98+
packagingOptions {
99+
exclude "META-INF/licenses/**"
100+
exclude "META-INF/AL2.0"
101+
exclude "META-INF/LGPL2.1"
102+
}
88103
}
89104

90105
dependencies {
91106
implementation Libs.Kotlin.stdlib
107+
implementation Libs.Kotlin.Coroutines.android
92108
implementation Libs.googleMaps
93109

94110
implementation Libs.AndroidX.Compose.runtime
@@ -98,12 +114,27 @@ dependencies {
98114
implementation Libs.AndroidX.Compose.layout
99115
implementation Libs.AndroidX.Compose.animation
100116
implementation Libs.AndroidX.UI.tooling
101-
102117
implementation Libs.Accompanist.coil
103118

119+
implementation Libs.AndroidX.Lifecycle.viewModelKtx
120+
implementation Libs.Hilt.android
121+
implementation Libs.Hilt.AndroidX.viewModel
122+
compileOnly Libs.AssistedInjection.dagger
123+
kapt Libs.Hilt.compiler
124+
kapt Libs.Hilt.AndroidX.compiler
125+
kapt Libs.AssistedInjection.processor
126+
127+
androidTestImplementation Libs.JUnit.junit
104128
androidTestImplementation Libs.AndroidX.Test.runner
105129
androidTestImplementation Libs.AndroidX.Test.espressoCore
106130
androidTestImplementation Libs.AndroidX.Test.rules
107131
androidTestImplementation Libs.AndroidX.Test.Ext.junit
132+
androidTestImplementation Libs.Kotlin.Coroutines.test
108133
androidTestImplementation Libs.AndroidX.Compose.uiTest
134+
androidTestImplementation Libs.Hilt.android
135+
androidTestImplementation Libs.Hilt.AndroidX.viewModel
136+
androidTestImplementation Libs.Hilt.testing
137+
kaptAndroidTest Libs.Hilt.compiler
138+
kaptAndroidTest Libs.Hilt.AndroidX.compiler
139+
kaptAndroidTest Libs.AssistedInjection.processor
109140
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright 2020 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package androidx.compose.samples.crane
18+
19+
import android.app.Application
20+
import android.content.Context
21+
import androidx.test.runner.AndroidJUnitRunner
22+
import dagger.hilt.android.testing.HiltTestApplication
23+
24+
class CustomTestRunner : AndroidJUnitRunner() {
25+
override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application {
26+
return super.newApplication(cl, HiltTestApplication::class.java.name, context)
27+
}
28+
}

Crane/app/src/androidTest/java/androidx/compose/samples/crane/calendar/CalendarTest.kt

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,66 +17,61 @@
1717
package androidx.compose.samples.crane.calendar
1818

1919
import androidx.compose.material.Surface
20-
import androidx.compose.samples.crane.base.ServiceLocator
21-
import androidx.compose.samples.crane.calendar.model.CalendarDay
22-
import androidx.compose.samples.crane.calendar.model.CalendarMonth
23-
import androidx.compose.samples.crane.calendar.model.DaySelected
2420
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus
2521
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus.FirstDay
2622
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus.FirstLastDay
2723
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus.LastDay
2824
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus.NoSelected
2925
import androidx.compose.samples.crane.calendar.model.DaySelectedStatus.Selected
26+
import androidx.compose.samples.crane.data.DatesRepository
27+
import androidx.compose.samples.crane.di.DispatchersModule
3028
import androidx.compose.samples.crane.ui.CraneTheme
3129
import androidx.ui.test.ComposeTestRule
3230
import androidx.ui.test.SemanticsMatcher
3331
import androidx.ui.test.assertLabelEquals
34-
import androidx.ui.test.createComposeRule
32+
import androidx.ui.test.createAndroidComposeRule
3533
import androidx.ui.test.onNodeWithLabel
3634
import androidx.ui.test.performClick
3735
import androidx.ui.test.performScrollTo
38-
import org.junit.After
36+
import dagger.hilt.android.testing.HiltAndroidRule
37+
import dagger.hilt.android.testing.HiltAndroidTest
38+
import dagger.hilt.android.testing.UninstallModules
3939
import org.junit.Before
4040
import org.junit.Rule
4141
import org.junit.Test
42+
import javax.inject.Inject
4243

44+
@UninstallModules(DispatchersModule::class)
45+
@HiltAndroidTest
4346
class CalendarTest {
4447

45-
@get:Rule
46-
val composeTestRule = createComposeRule(disableTransitions = true)
47-
48-
var dateSelected = ""
49-
private val onDayClicked: (CalendarDay, CalendarMonth) -> Unit = { day, month ->
50-
dateSelected = "${month.name} ${day.value}"
51-
ServiceLocator.datesSelected.daySelected(
52-
DaySelected(
53-
day = day.value.toInt(),
54-
month = month
55-
)
56-
)
57-
}
48+
@get:Rule(order = 0)
49+
var hiltRule = HiltAndroidRule(this)
50+
51+
@get:Rule(order = 1)
52+
val composeTestRule = createAndroidComposeRule<CalendarActivity>()
53+
54+
@Inject
55+
lateinit var datesRepository: DatesRepository
5856

5957
@Before
6058
fun setUp() {
59+
hiltRule.inject()
60+
6161
composeTestRule.setContent {
6262
CraneTheme {
6363
Surface {
64-
Calendar(onDayClicked)
64+
CalendarScreen(onBackPressed = {})
6565
}
6666
}
6767
}
6868
}
6969

70-
@After
71-
fun tearDown() {
72-
ServiceLocator.datesSelected.clearDates()
73-
}
74-
7570
@Test
7671
fun scrollsToTheBottom() {
7772
composeTestRule.onNodeWithLabel("January 1").assertExists()
7873
composeTestRule.onNodeWithLabel("December 31").performScrollTo().performClick()
79-
assert(dateSelected == "December 31")
74+
assert(datesRepository.datesSelected.toString() == "Dec 31")
8075
}
8176

8277
@Test

Crane/app/src/androidTest/java/androidx/compose/samples/crane/details/DetailsActivityTest.kt

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
package androidx.compose.samples.crane.details
1818

1919
import androidx.compose.samples.crane.R
20+
import androidx.compose.samples.crane.data.DestinationsRepository
2021
import androidx.compose.samples.crane.data.ExploreModel
2122
import androidx.compose.samples.crane.data.MADRID
23+
import androidx.compose.samples.crane.di.DispatchersModule
2224
import androidx.test.espresso.Espresso.onView
2325
import androidx.test.espresso.assertion.ViewAssertions.matches
2426
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
@@ -31,16 +33,30 @@ import androidx.ui.test.onNodeWithText
3133
import com.google.android.libraries.maps.MapView
3234
import com.google.android.libraries.maps.model.CameraPosition
3335
import com.google.android.libraries.maps.model.LatLng
36+
import dagger.hilt.android.testing.HiltAndroidRule
37+
import dagger.hilt.android.testing.HiltAndroidTest
38+
import dagger.hilt.android.testing.UninstallModules
39+
import org.junit.Before
3440
import org.junit.Rule
3541
import org.junit.Test
3642
import java.util.concurrent.CountDownLatch
43+
import javax.inject.Inject
3744

45+
@UninstallModules(DispatchersModule::class)
46+
@HiltAndroidTest
3847
class DetailsActivityTest {
3948

40-
private val expectedDescription = "description"
41-
private val testExploreModel = ExploreModel(MADRID, expectedDescription, "imageUrl")
49+
@Inject
50+
lateinit var destinationsRepository: DestinationsRepository
51+
lateinit var cityDetails: ExploreModel
4252

43-
@get:Rule
53+
private val city = MADRID
54+
private val testExploreModel = ExploreModel(city, "description", "imageUrl")
55+
56+
@get:Rule(order = 0)
57+
var hiltRule = HiltAndroidRule(this)
58+
59+
@get:Rule(order = 1)
4460
val composeTestRule = AndroidComposeTestRule(
4561
ActivityScenarioRule<DetailsActivity>(
4662
createDetailsActivityIntent(
@@ -50,10 +66,16 @@ class DetailsActivityTest {
5066
)
5167
)
5268

69+
@Before
70+
fun setUp() {
71+
hiltRule.inject()
72+
cityDetails = destinationsRepository.getDestination(MADRID.name)!!
73+
}
74+
5375
@Test
5476
fun mapView_cameraPositioned() {
55-
composeTestRule.onNodeWithText(MADRID.nameToDisplay).assertIsDisplayed()
56-
composeTestRule.onNodeWithText(expectedDescription).assertIsDisplayed()
77+
composeTestRule.onNodeWithText(cityDetails.city.nameToDisplay).assertIsDisplayed()
78+
composeTestRule.onNodeWithText(cityDetails.description).assertIsDisplayed()
5779
onView(withId(R.id.map)).check(matches(isDisplayed()))
5880

5981
var cameraPosition: CameraPosition? = null
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2020 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
@file:Suppress("DEPRECATION")
18+
19+
package androidx.compose.samples.crane.di
20+
21+
import dagger.Module
22+
import dagger.Provides
23+
import dagger.hilt.InstallIn
24+
import dagger.hilt.android.components.ApplicationComponent
25+
import kotlinx.coroutines.CoroutineDispatcher
26+
import kotlinx.coroutines.Dispatchers
27+
import kotlinx.coroutines.ExperimentalCoroutinesApi
28+
29+
@OptIn(ExperimentalCoroutinesApi::class)
30+
@Module
31+
@InstallIn(ApplicationComponent::class)
32+
class TestDispatchersModule {
33+
34+
@Provides
35+
@DefaultDispatcher
36+
fun provideDefaultDispatcher(): CoroutineDispatcher = Dispatchers.Unconfined
37+
}

0 commit comments

Comments
 (0)