Merge branch 'android:main' into loading-progress-for-image

pull/850/head^2
Qamar A. Safadi 1 year ago committed by GitHub
commit 2db3e0c804
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -121,12 +121,3 @@ dependencies {
implementation(libs.kotlinx.coroutines.guava)
implementation(libs.coil.kt)
}
// androidx.test is forcing JUnit, 4.12. This forces it to use 4.13
configurations.configureEach {
resolutionStrategy {
force(libs.junit4)
// Temporary workaround for https://issuetracker.google.com/174733673
force("org.objenesis:objenesis:2.6")
}
}

@ -43,6 +43,6 @@ class MainActivityViewModel @Inject constructor(
}
sealed interface MainActivityUiState {
object Loading : MainActivityUiState
data object Loading : MainActivityUiState
data class Success(val userData: UserData) : MainActivityUiState
}

@ -21,7 +21,6 @@ import com.google.samples.apps.nowinandroid.configureGradleManagedDevices
import com.google.samples.apps.nowinandroid.configureKotlinAndroid
import com.google.samples.apps.nowinandroid.configurePrintApksTask
import com.google.samples.apps.nowinandroid.disableUnnecessaryAndroidTests
import com.google.samples.apps.nowinandroid.libs
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
@ -46,13 +45,6 @@ class AndroidLibraryConventionPlugin : Plugin<Project> {
configurePrintApksTask(this)
disableUnnecessaryAndroidTests(target)
}
configurations.configureEach {
resolutionStrategy {
force(libs.findLibrary("junit4").get())
// Temporary workaround for https://issuetracker.google.com/174733673
force("org.objenesis:objenesis:2.6")
}
}
dependencies {
add("androidTestImplementation", kotlin("test"))
add("testImplementation", kotlin("test"))

@ -1,21 +0,0 @@
/*
* 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.google.samples.apps.nowinandroid.core.decoder
interface StringDecoder {
fun decodeString(encodedString: String): String
}

@ -1,24 +0,0 @@
/*
* 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.google.samples.apps.nowinandroid.core.decoder
import android.net.Uri
import javax.inject.Inject
class UriDecoder @Inject constructor() : StringDecoder {
override fun decodeString(encodedString: String): String = Uri.decode(encodedString)
}

@ -1,31 +0,0 @@
/*
* 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.google.samples.apps.nowinandroid.core.decoder.di
import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder
import com.google.samples.apps.nowinandroid.core.decoder.UriDecoder
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
abstract class StringDecoderModule {
@Binds
abstract fun bindStringDecoder(uriDecoder: UriDecoder): StringDecoder
}

@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.onStart
sealed interface Result<out T> {
data class Success<T>(val data: T) : Result<T>
data class Error(val exception: Throwable? = null) : Result<Nothing>
object Loading : Result<Nothing>
data object Loading : Result<Nothing>
}
fun <T> Flow<T>.asResult(): Flow<Result<T>> {

@ -1,24 +0,0 @@
/*
* 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.google.samples.apps.nowinandroid.core.testing.decoder
import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder
import javax.inject.Inject
class FakeStringDecoder @Inject constructor() : StringDecoder {
override fun decodeString(encodedString: String): String = encodedString
}

@ -1,35 +0,0 @@
/*
* 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.google.samples.apps.nowinandroid.core.testing.di
import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder
import com.google.samples.apps.nowinandroid.core.decoder.di.StringDecoderModule
import com.google.samples.apps.nowinandroid.core.testing.decoder.FakeStringDecoder
import dagger.Binds
import dagger.Module
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [StringDecoderModule::class],
)
abstract class TestStringDecoderModule {
@Binds
abstract fun bindsStringDecoder(fakeStringDecoder: FakeStringDecoder): StringDecoder
}

@ -112,7 +112,7 @@ sealed interface NewsFeedUiState {
/**
* The feed is still loading.
*/
object Loading : NewsFeedUiState
data object Loading : NewsFeedUiState
/**
* The feed is loaded with the given list of news resources.

@ -25,17 +25,17 @@ sealed interface OnboardingUiState {
/**
* The onboarding state is loading.
*/
object Loading : OnboardingUiState
data object Loading : OnboardingUiState
/**
* The onboarding state was unable to load.
*/
object LoadFailed : OnboardingUiState
data object LoadFailed : OnboardingUiState
/**
* There is no onboarding state.
*/
object NotShown : OnboardingUiState
data object NotShown : OnboardingUiState
/**
* There is a onboarding state, with the given lists of topics.

@ -53,11 +53,11 @@ class InterestsViewModel @Inject constructor(
}
sealed interface InterestsUiState {
object Loading : InterestsUiState
data object Loading : InterestsUiState
data class Interests(
val topics: List<FollowableTopic>,
) : InterestsUiState
object Empty : InterestsUiState
data object Empty : InterestsUiState
}

@ -23,7 +23,6 @@ import com.google.samples.apps.nowinandroid.core.data.repository.NewsResourceQue
import com.google.samples.apps.nowinandroid.core.data.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserDataRepository
import com.google.samples.apps.nowinandroid.core.data.repository.UserNewsResourceRepository
import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder
import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.model.data.UserNewsResource
@ -43,13 +42,12 @@ import javax.inject.Inject
@HiltViewModel
class TopicViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
stringDecoder: StringDecoder,
private val userDataRepository: UserDataRepository,
topicsRepository: TopicsRepository,
userNewsResourceRepository: UserNewsResourceRepository,
) : ViewModel() {
private val topicArgs: TopicArgs = TopicArgs(savedStateHandle, stringDecoder)
private val topicArgs: TopicArgs = TopicArgs(savedStateHandle)
val topicId = topicArgs.topicId

@ -16,7 +16,6 @@
package com.google.samples.apps.nowinandroid.feature.topic.navigation
import android.net.Uri
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.SavedStateHandle
import androidx.navigation.NavController
@ -24,19 +23,23 @@ import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavType
import androidx.navigation.compose.composable
import androidx.navigation.navArgument
import com.google.samples.apps.nowinandroid.core.decoder.StringDecoder
import com.google.samples.apps.nowinandroid.feature.topic.TopicRoute
import java.net.URLDecoder
import java.net.URLEncoder
import kotlin.text.Charsets.UTF_8
private val URL_CHARACTER_ENCODING = UTF_8.name()
@VisibleForTesting
internal const val topicIdArg = "topicId"
internal class TopicArgs(val topicId: String) {
constructor(savedStateHandle: SavedStateHandle, stringDecoder: StringDecoder) :
this(stringDecoder.decodeString(checkNotNull(savedStateHandle[topicIdArg])))
constructor(savedStateHandle: SavedStateHandle) :
this(URLDecoder.decode(checkNotNull(savedStateHandle[topicIdArg]), URL_CHARACTER_ENCODING))
}
fun NavController.navigateToTopic(topicId: String) {
val encodedId = Uri.encode(topicId)
val encodedId = URLEncoder.encode(topicId, URL_CHARACTER_ENCODING)
this.navigate("topic_route/$encodedId") {
launchSingleTop = true
}

@ -22,7 +22,6 @@ import com.google.samples.apps.nowinandroid.core.model.data.FollowableTopic
import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType.Video
import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.core.testing.decoder.FakeStringDecoder
import com.google.samples.apps.nowinandroid.core.testing.repository.TestNewsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.core.testing.repository.TestUserDataRepository
@ -63,7 +62,6 @@ class TopicViewModelTest {
fun setup() {
viewModel = TopicViewModel(
savedStateHandle = SavedStateHandle(mapOf(topicIdArg to testInputTopics[0].topic.id)),
stringDecoder = FakeStringDecoder(),
userDataRepository = userDataRepository,
topicsRepository = topicsRepository,
userNewsResourceRepository = userNewsResourceRepository,

Loading…
Cancel
Save