Modularise the app

Change-Id: I63791eaf27d08a837598d774df53c96bb01b5864
pull/2/head
Simona Stojanovic 3 years ago
parent 1b06dc97ea
commit 1411b1576b

@ -17,11 +17,8 @@ plugins {
id 'com.android.application' id 'com.android.application'
id 'kotlin-android' id 'kotlin-android'
id 'kotlin-kapt' id 'kotlin-kapt'
id 'kotlinx-serialization'
id 'jacoco' id 'jacoco'
id 'dagger.hilt.android.plugin' id 'dagger.hilt.android.plugin'
alias(libs.plugins.protobuf)
alias(libs.plugins.ksp)
} }
def jacocoTestReport = tasks.create("jacocoTestReport") def jacocoTestReport = tasks.create("jacocoTestReport")
@ -37,7 +34,7 @@ android {
versionName "0.0.1" // X.Y.Z; X = Major, Y = minor, Z = Patch level versionName "0.0.1" // X.Y.Z; X = Major, Y = minor, Z = Patch level
// Custom test runner to set up Hilt dependency graph // Custom test runner to set up Hilt dependency graph
testInstrumentationRunner "com.google.samples.apps.nowinandroid.NiaTestRunner" testInstrumentationRunner "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"
vectorDrawables { vectorDrawables {
useSupportLibrary true useSupportLibrary true
} }
@ -112,81 +109,34 @@ android {
} }
} }
// Setup protobuf configuration, generating lite Java and Kotlin classes
protobuf {
protoc {
artifact = libs.protobuf.protoc.get()
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
kotlin {
option "lite"
}
}
}
}
}
dependencies { dependencies {
coreLibraryDesugaring libs.android.desugarJdkLibs implementation project(':feature-following')
implementation project(':feature-foryou')
implementation project(':core-ui')
implementation libs.kotlinx.coroutines.android androidTestImplementation project(':core-testing')
implementation libs.kotlinx.datetime implementation project(':core-datastore-test')
implementation libs.kotlinx.serialization.json
coreLibraryDesugaring libs.android.desugarJdkLibs
implementation libs.androidx.activity.compose implementation libs.androidx.activity.compose
implementation libs.androidx.core.ktx implementation libs.androidx.core.ktx
implementation libs.androidx.dataStore
implementation libs.androidx.appcompat implementation libs.androidx.appcompat
implementation libs.androidx.hilt.navigation.compose implementation libs.androidx.hilt.navigation.compose
implementation libs.androidx.lifecycle.viewModelCompose
implementation libs.androidx.navigation.compose implementation libs.androidx.navigation.compose
implementation libs.material3 implementation libs.material3
implementation libs.accompanist.flowlayout
implementation libs.androidx.compose.foundation.layout
// TODO (M3): Remove this dependency when all components are available
implementation libs.androidx.compose.material
implementation libs.androidx.compose.material.iconsExtended
implementation libs.androidx.compose.material3
implementation libs.androidx.compose.ui.tooling
implementation libs.androidx.compose.ui.util
implementation libs.androidx.compose.runtime
implementation libs.androidx.compose.runtime.livedata
implementation libs.hilt.android implementation libs.hilt.android
kapt libs.hilt.compiler kapt libs.hilt.compiler
implementation libs.room.runtime
implementation libs.room.ktx
ksp libs.room.compiler
implementation libs.protobuf.kotlin.lite
debugImplementation libs.androidx.compose.ui.testManifest
testImplementation libs.junit4
testImplementation libs.mockk
testImplementation libs.androidx.test.core
testImplementation libs.kotlinx.coroutines.test
testImplementation libs.turbine
androidTestImplementation libs.androidx.test.espresso.core
androidTestImplementation libs.androidx.test.runner
androidTestImplementation libs.androidx.test.rules
androidTestImplementation libs.androidx.compose.ui.test
androidTestImplementation libs.hilt.android.testing
kaptAndroidTest libs.hilt.compiler kaptAndroidTest libs.hilt.compiler
// androidx.test is forcing JUnit, 4.12. This forces it to use 4.13 // androidx.test is forcing JUnit, 4.12. This forces it to use 4.13
configurations.configureEach { configurations.configureEach {
resolutionStrategy { resolutionStrategy {
force libs.junit4 force libs.junit4
// Temporary workaround for https://issuetracker.google.com/174733673
force 'org.objenesis:objenesis:2.6'
} }
} }
} }

@ -1,65 +0,0 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
# Keep `Companion` object fields of serializable classes.
# This avoids serializer lookup through `getDeclaredClasses` as done for named companion objects.
-if @kotlinx.serialization.Serializable class **
-keepclassmembers class <1> {
static <1>$Companion Companion;
}
# Keep `serializer()` on companion objects (both default and named) of serializable classes.
-if @kotlinx.serialization.Serializable class ** {
static **$* *;
}
-keepclassmembers class <1>$<3> {
kotlinx.serialization.KSerializer serializer(...);
}
# Keep `INSTANCE.serializer()` of serializable objects.
-if @kotlinx.serialization.Serializable class ** {
public static ** INSTANCE;
}
-keepclassmembers class <1> {
public static <1> INSTANCE;
kotlinx.serialization.KSerializer serializer(...);
}
# @Serializable and @Polymorphic are used at runtime for polymorphic serialization.
-keepattributes RuntimeVisibleAnnotations,AnnotationDefault
# Serializer for classes with named companion objects are retrieved using `getDeclaredClasses`.
# If you have any, uncomment and replace classes with those containing named companion objects.
#-keepattributes InnerClasses # Needed for `getDeclaredClasses`.
#-if @kotlinx.serialization.Serializable class
#com.example.myapplication.HasNamedCompanion, # <-- List serializable classes with named companions.
#com.example.myapplication.HasNamedCompanion2
#{
# static **$* *;
#}
#-keepnames class <1>$$serializer { # -keepnames suffices; class is kept when serializer() is kept.
# static <1>$$serializer INSTANCE;
#}
# Enable protobuf-related optimizations.
-shrinkunusedprotofields

@ -1,81 +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.di
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import com.google.samples.apps.nowinandroid.data.UserPreferences
import com.google.samples.apps.nowinandroid.data.UserPreferencesSerializer
import com.google.samples.apps.nowinandroid.data.fake.FakeNewsRepository
import com.google.samples.apps.nowinandroid.data.fake.FakeTopicsRepository
import com.google.samples.apps.nowinandroid.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.data.repository.TopicsRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import javax.inject.Singleton
import kotlinx.serialization.json.Json
import org.junit.rules.TemporaryFolder
/**
* The [TestAppModule] replaces [AppModule] during instrumentation tests. It creates test doubles
* where necessary. It also includes logic to prevent multiple data stores with the same file name
* from being created during one test execution context.
*/
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [AppModule::class]
)
interface TestAppModule {
// Use a fake repository as a test double, so we don't have a network dependency.
@Binds
fun bindsTopicRepository(fakeTopicsRepository: FakeTopicsRepository): TopicsRepository
// Use a fake repository as a test double, so we don't have a network dependency.
@Binds
fun bindsNewsResourceRepository(fakeNewsRepository: FakeNewsRepository): NewsRepository
// Use the default dispatchers. For the high-level UI tests, we don't want to override these.
@Binds
fun bindsNiaDispatchers(defaultNiaDispatchers: DefaultNiaDispatchers): NiaDispatchers
companion object {
@Provides
@Singleton
fun providesUserPreferencesDataStore(
userPreferencesSerializer: UserPreferencesSerializer,
tmpFolder: TemporaryFolder
): DataStore<UserPreferences> {
return DataStoreFactory.create(
serializer = userPreferencesSerializer,
) {
tmpFolder.newFile("user_preferences_test.pb")
}
}
@Provides
@Singleton
fun providesNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
}
}

@ -1,81 +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.di
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.google.samples.apps.nowinandroid.data.UserPreferences
import com.google.samples.apps.nowinandroid.data.UserPreferencesSerializer
import com.google.samples.apps.nowinandroid.data.fake.FakeNewsRepository
import com.google.samples.apps.nowinandroid.data.fake.FakeNiANetwork
import com.google.samples.apps.nowinandroid.data.fake.FakeTopicsRepository
import com.google.samples.apps.nowinandroid.data.network.NiANetwork
import com.google.samples.apps.nowinandroid.data.repository.NewsRepository
import com.google.samples.apps.nowinandroid.data.repository.TopicsRepository
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import kotlinx.serialization.json.Json
@Module
@InstallIn(SingletonComponent::class)
interface AppModule {
@Binds
fun bindsNiANetwork(
fakeNiANetwork: FakeNiANetwork
): NiANetwork
@Binds
fun bindsTopicRepository(
fakeTopicsRepository: FakeTopicsRepository
): TopicsRepository
@Binds
fun bindsNewsResourceRepository(
fakeNewsRepository: FakeNewsRepository
): NewsRepository
@Binds
fun bindsNiaDispatchers(defaultNiaDispatchers: DefaultNiaDispatchers): NiaDispatchers
companion object {
@Provides
@Singleton
fun providesUserPreferencesDataStore(
@ApplicationContext context: Context,
userPreferencesSerializer: UserPreferencesSerializer
): DataStore<UserPreferences> =
DataStoreFactory.create(
serializer = userPreferencesSerializer
) {
context.dataStoreFile("user_preferences.pb")
}
@Provides
@Singleton
fun providesNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
}
}

@ -51,7 +51,8 @@ import androidx.compose.ui.unit.dp
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.R
import com.google.samples.apps.nowinandroid.ui.theme.NiaTheme import com.google.samples.apps.nowinandroid.core.ui.ClearRippleTheme
import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class)
@Composable @Composable

@ -23,8 +23,8 @@ import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.google.samples.apps.nowinandroid.ui.following.FollowingRoute import com.google.samples.apps.nowinandroid.feature.following.FollowingRoute
import com.google.samples.apps.nowinandroid.ui.foryou.ForYouRoute import com.google.samples.apps.nowinandroid.feature.foryou.ForYouRoute
/** /**
* Top-level navigation graph. Navigation is organized as explained at * Top-level navigation graph. Navigation is organized as explained at

@ -15,22 +15,4 @@
--> -->
<resources> <resources>
<string name="app_name">Now in Android</string> <string name="app_name">Now in Android</string>
<string name="for_you">For you</string>
<string name="episodes">Episodes</string>
<string name="saved">Saved</string>
<string name="done">Done</string>
<string name="for_you_loading">Loading for you…</string>
<string name="navigate_up">Navigate up</string>
<!-- NewsResource Card -->
<string name="bookmark">Bookmark</string>
<string name="unbookmark">Unbookmark</string>
<!-- Following-->
<string name="following">Following</string>
<string name="following_loading">Loading topics</string>
<string name="following_error_header">"Error loading topics"</string>
<string name="following_topic_card_icon_content_desc">Topic icon</string>
<string name="following_topic_card_follow_button_content_desc">Follow Topic button</string>
<string name="following_topic_card_unfollow_button_content_desc">Unfollow Topic button</string>
</resources> </resources>

@ -49,7 +49,7 @@ subprojects {
target '**/*.kt' target '**/*.kt'
targetExclude("$buildDir/**/*.kt") targetExclude("$buildDir/**/*.kt")
targetExclude('bin/**/*.kt') targetExclude('bin/**/*.kt')
targetExclude("$rootDir/app/src/main/java/com/google/samples/apps/nowinandroid/data/fake/FakeData.kt") targetExclude("$rootDir/core-network/src/main/java/com/google/samples/apps/nowinandroid/core/network/fake/FakeData.kt")
ktlint(libs.versions.ktlint.get()).userData([android: "true"]) ktlint(libs.versions.ktlint.get()).userData([android: "true"])
licenseHeaderFile rootProject.file('spotless/copyright.kt') licenseHeaderFile rootProject.file('spotless/copyright.kt')
} }

@ -0,0 +1 @@
/build

@ -0,0 +1,35 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.common">
</manifest>

@ -0,0 +1 @@
/build

@ -0,0 +1,52 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
alias(libs.plugins.ksp)
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation project(':core-model')
implementation libs.room.runtime
implementation libs.room.ktx
ksp libs.room.compiler
implementation libs.kotlinx.coroutines.android
implementation libs.kotlinx.datetime
implementation libs.hilt.android
kapt libs.hilt.compiler
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.database">
</manifest>

@ -14,13 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.di package com.google.samples.apps.nowinandroid.core.database
import com.google.samples.apps.nowinandroid.data.local.NiADatabase import com.google.samples.apps.nowinandroid.core.database.dao.AuthorDao
import com.google.samples.apps.nowinandroid.data.local.dao.AuthorDao import com.google.samples.apps.nowinandroid.core.database.dao.EpisodeDao
import com.google.samples.apps.nowinandroid.data.local.dao.EpisodeDao import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDao
import com.google.samples.apps.nowinandroid.data.local.dao.NewsResourceDao import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao
import com.google.samples.apps.nowinandroid.data.local.dao.TopicDao
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn

@ -14,11 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.di package com.google.samples.apps.nowinandroid.core.database
import android.content.Context import android.content.Context
import androidx.room.Room import androidx.room.Room
import com.google.samples.apps.nowinandroid.data.local.NiADatabase
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn

@ -14,24 +14,24 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local package com.google.samples.apps.nowinandroid.core.database
import androidx.room.Database import androidx.room.Database
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverters import androidx.room.TypeConverters
import com.google.samples.apps.nowinandroid.data.local.dao.AuthorDao import com.google.samples.apps.nowinandroid.core.database.dao.AuthorDao
import com.google.samples.apps.nowinandroid.data.local.dao.EpisodeDao import com.google.samples.apps.nowinandroid.core.database.dao.EpisodeDao
import com.google.samples.apps.nowinandroid.data.local.dao.NewsResourceDao import com.google.samples.apps.nowinandroid.core.database.dao.NewsResourceDao
import com.google.samples.apps.nowinandroid.data.local.dao.TopicDao import com.google.samples.apps.nowinandroid.core.database.dao.TopicDao
import com.google.samples.apps.nowinandroid.data.local.entities.AuthorEntity import com.google.samples.apps.nowinandroid.core.database.util.InstantConverter
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeAuthorCrossRef import com.google.samples.apps.nowinandroid.core.database.util.NewsResourceTypeConverter
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeEntity import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceAuthorCrossRef import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeAuthorCrossRef
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceEntity import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceTopicCrossRef import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceAuthorCrossRef
import com.google.samples.apps.nowinandroid.data.local.entities.TopicEntity import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
import com.google.samples.apps.nowinandroid.data.local.utilities.InstantConverter import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceTopicCrossRef
import com.google.samples.apps.nowinandroid.data.local.utilities.NewsResourceTypeConverter import com.google.samples.apps.nowinandroid.core.model.entities.TopicEntity
@Database( @Database(
entities = [ entities = [

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.dao package com.google.samples.apps.nowinandroid.core.database.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.google.samples.apps.nowinandroid.data.local.entities.AuthorEntity import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.dao package com.google.samples.apps.nowinandroid.core.database.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeEntity import com.google.samples.apps.nowinandroid.core.model.data.Episode
import com.google.samples.apps.nowinandroid.data.model.Episode import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.dao package com.google.samples.apps.nowinandroid.core.database.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceEntity import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.data.model.NewsResource import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.dao package com.google.samples.apps.nowinandroid.core.database.dao
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.Query import androidx.room.Query
import com.google.samples.apps.nowinandroid.data.local.entities.TopicEntity import com.google.samples.apps.nowinandroid.core.model.entities.TopicEntity
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.utilities package com.google.samples.apps.nowinandroid.core.database.util
import androidx.room.TypeConverter import androidx.room.TypeConverter
import com.google.samples.apps.nowinandroid.data.model.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
class InstantConverter { class InstantConverter {

@ -0,0 +1,55 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation project(':core-datastore')
implementation project(':core-testing')
implementation libs.androidx.dataStore
implementation libs.hilt.android
kapt libs.hilt.compiler
kaptAndroidTest libs.hilt.compiler
configurations.configureEach {
resolutionStrategy {
// Temporary workaround for https://issuetracker.google.com/174733673
force 'org.objenesis:objenesis:2.6'
}
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.datastore.test">
</manifest>

@ -0,0 +1,50 @@
/*
* 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.datastore.test
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferencesSerializer
import com.google.samples.apps.nowinandroid.core.datastore.di.DataStoreModule
import dagger.Module
import dagger.Provides
import dagger.hilt.components.SingletonComponent
import dagger.hilt.testing.TestInstallIn
import javax.inject.Singleton
import org.junit.rules.TemporaryFolder
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [DataStoreModule::class]
)
object TestDataStoreModule {
@Provides
@Singleton
fun providesUserPreferencesDataStore(
userPreferencesSerializer: UserPreferencesSerializer,
tmpFolder: TemporaryFolder
): DataStore<UserPreferences> {
return DataStoreFactory.create(
serializer = userPreferencesSerializer,
) {
tmpFolder.newFile("user_preferences_test.pb")
}
}
}

@ -0,0 +1 @@
/build

@ -0,0 +1,70 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
alias(libs.plugins.protobuf)
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
// Setup protobuf configuration, generating lite Java and Kotlin classes
protobuf {
protoc {
artifact = libs.protobuf.protoc.get()
}
generateProtoTasks {
all().each { task ->
task.builtins {
java {
option "lite"
}
kotlin {
option "lite"
}
}
}
}
}
dependencies {
testImplementation project(':core-testing')
implementation libs.kotlinx.coroutines.android
implementation libs.androidx.dataStore
implementation libs.protobuf.kotlin.lite
implementation libs.hilt.android
kapt libs.hilt.compiler
kaptAndroidTest libs.hilt.compiler
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.datastore">
</manifest>

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data package com.google.samples.apps.nowinandroid.core.datastore
import android.util.Log import android.util.Log
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data package com.google.samples.apps.nowinandroid.core.datastore
import androidx.datastore.core.CorruptionException import androidx.datastore.core.CorruptionException
import androidx.datastore.core.Serializer import androidx.datastore.core.Serializer

@ -0,0 +1,47 @@
/*
* 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.datastore.di
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.core.DataStoreFactory
import androidx.datastore.dataStoreFile
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferences
import com.google.samples.apps.nowinandroid.core.datastore.UserPreferencesSerializer
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
object DataStoreModule {
@Provides
@Singleton
fun providesUserPreferencesDataStore(
@ApplicationContext context: Context,
userPreferencesSerializer: UserPreferencesSerializer
): DataStore<UserPreferences> =
DataStoreFactory.create(
serializer = userPreferencesSerializer
) {
context.dataStoreFile("user_preferences.pb")
}
}

@ -16,7 +16,7 @@
syntax = "proto3"; syntax = "proto3";
option java_package = "com.google.samples.apps.nowinandroid.data"; option java_package = "com.google.samples.apps.nowinandroid.core.datastore";
option java_multiple_files = true; option java_multiple_files = true;
message UserPreferences { message UserPreferences {

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data package com.google.samples.apps.nowinandroid.core.datastore
import androidx.datastore.core.CorruptionException import androidx.datastore.core.CorruptionException
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream

@ -0,0 +1 @@
/build

@ -0,0 +1,52 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlinx-serialization'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation project(':core-model')
implementation project(':core-datastore')
implementation project(':core-network')
testImplementation project(':core-testing')
implementation libs.kotlinx.coroutines.android
implementation libs.kotlinx.serialization.json
implementation libs.hilt.android
kapt libs.hilt.compiler
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.domain">
</manifest>

@ -0,0 +1,41 @@
/*
* 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.domain.di
import com.google.samples.apps.nowinandroid.core.domain.repository.FakeNewsRepository
import com.google.samples.apps.nowinandroid.core.domain.repository.FakeTopicsRepository
import com.google.samples.apps.nowinandroid.core.domain.repository.NewsRepository
import com.google.samples.apps.nowinandroid.core.domain.repository.TopicsRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
interface DomainModule {
@Binds
fun bindsTopicRepository(
fakeTopicsRepository: FakeTopicsRepository
): TopicsRepository
@Binds
fun bindsNewsResourceRepository(
fakeNewsRepository: FakeNewsRepository
): NewsRepository
}

@ -14,11 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.domain.repository
import com.google.samples.apps.nowinandroid.data.model.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.data.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers
import com.google.samples.apps.nowinandroid.di.NiaDispatchers
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.flowOf

@ -14,13 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.domain.repository
import com.google.samples.apps.nowinandroid.data.NiaPreferences import com.google.samples.apps.nowinandroid.core.datastore.NiaPreferences
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.data.network.NetworkTopic import com.google.samples.apps.nowinandroid.core.model.network.NetworkTopic
import com.google.samples.apps.nowinandroid.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers
import com.google.samples.apps.nowinandroid.di.NiaDispatchers import com.google.samples.apps.nowinandroid.core.network.fake.FakeDataSource
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flow

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.repository package com.google.samples.apps.nowinandroid.core.domain.repository
import com.google.samples.apps.nowinandroid.data.model.NewsResource import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
/** /**

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.repository package com.google.samples.apps.nowinandroid.core.domain.repository
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
interface TopicsRepository { interface TopicsRepository {

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.domain.repository
import com.google.samples.apps.nowinandroid.di.DefaultNiaDispatchers import com.google.samples.apps.nowinandroid.core.network.DefaultNiaDispatchers
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Before import org.junit.Before

@ -0,0 +1 @@
/build

@ -0,0 +1,49 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlinx-serialization'
alias(libs.plugins.ksp)
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
testImplementation project(':core-testing')
implementation libs.room.runtime
implementation libs.room.ktx
ksp libs.room.compiler
implementation libs.kotlinx.coroutines.android
implementation libs.kotlinx.datetime
implementation libs.kotlinx.serialization.json
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.model">
</manifest>

@ -14,15 +14,15 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.model package com.google.samples.apps.nowinandroid.core.model.data
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Junction import androidx.room.Junction
import androidx.room.Relation import androidx.room.Relation
import com.google.samples.apps.nowinandroid.data.local.entities.AuthorEntity import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeAuthorCrossRef import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeAuthorCrossRef
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeEntity import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceEntity import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
/** /**
* External data layer representation of an NiA episode * External data layer representation of an NiA episode

@ -14,17 +14,17 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.model package com.google.samples.apps.nowinandroid.core.model.data
import androidx.room.Embedded import androidx.room.Embedded
import androidx.room.Junction import androidx.room.Junction
import androidx.room.Relation import androidx.room.Relation
import com.google.samples.apps.nowinandroid.data.local.entities.AuthorEntity import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeEntity import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceAuthorCrossRef import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceAuthorCrossRef
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceEntity import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceTopicCrossRef import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceTopicCrossRef
import com.google.samples.apps.nowinandroid.data.local.entities.TopicEntity import com.google.samples.apps.nowinandroid.core.model.entities.TopicEntity
/** /**
* External data layer representation of a fully populated NiA news resource * External data layer representation of a fully populated NiA news resource

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.model package com.google.samples.apps.nowinandroid.core.model.data
/** /**
* Type for [NewsResource] * Type for [NewsResource]

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.model package com.google.samples.apps.nowinandroid.core.model.data
/** /**
* External data layer representation of a NiA Topic * External data layer representation of a NiA Topic

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.ColumnInfo import androidx.room.ColumnInfo
import androidx.room.Entity import androidx.room.Entity

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.local.entities package com.google.samples.apps.nowinandroid.core.model.entities
import androidx.room.Entity import androidx.room.Entity
import androidx.room.Index import androidx.room.Index

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network.utilities package com.google.samples.apps.nowinandroid.core.model.network
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.datetime.toInstant import kotlinx.datetime.toInstant

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.model.network
import com.google.samples.apps.nowinandroid.data.local.entities.AuthorEntity import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
/** /**

@ -14,11 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.model.network
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import com.google.samples.apps.nowinandroid.data.local.entities.EpisodeEntity import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import com.google.samples.apps.nowinandroid.data.network.utilities.InstantSerializer
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

@ -14,10 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.model.network
import com.google.samples.apps.nowinandroid.data.local.entities.NewsResourceEntity import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
import com.google.samples.apps.nowinandroid.data.network.utilities.InstantSerializer
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.model.network
import com.google.samples.apps.nowinandroid.data.local.entities.TopicEntity import com.google.samples.apps.nowinandroid.core.model.entities.TopicEntity
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
/** /**

@ -14,9 +14,16 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.model
import com.google.samples.apps.nowinandroid.data.model.NewsResourceType import com.google.samples.apps.nowinandroid.core.model.data.NewsResourceType
import com.google.samples.apps.nowinandroid.core.model.network.NetworkAuthor
import com.google.samples.apps.nowinandroid.core.model.network.NetworkEpisode
import com.google.samples.apps.nowinandroid.core.model.network.NetworkEpisodeExpanded
import com.google.samples.apps.nowinandroid.core.model.network.NetworkNewsResource
import com.google.samples.apps.nowinandroid.core.model.network.NetworkNewsResourceExpanded
import com.google.samples.apps.nowinandroid.core.model.network.NetworkTopic
import com.google.samples.apps.nowinandroid.core.model.network.asEntity
import kotlinx.datetime.Instant import kotlinx.datetime.Instant
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test

@ -0,0 +1 @@
/build

@ -0,0 +1,51 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'kotlinx-serialization'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation project(':core-model')
testImplementation project(':core-testing')
implementation libs.kotlinx.coroutines.android
implementation libs.kotlinx.serialization.json
implementation libs.kotlinx.datetime
implementation libs.hilt.android
kapt libs.hilt.compiler
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.network">
</manifest>

@ -14,7 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.network package com.google.samples.apps.nowinandroid.core.network
import com.google.samples.apps.nowinandroid.core.model.network.NetworkNewsResource
import com.google.samples.apps.nowinandroid.core.model.network.NetworkTopic
/** /**
* Interface representing network calls to the NIA backend * Interface representing network calls to the NIA backend

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.di package com.google.samples.apps.nowinandroid.core.network
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher

@ -0,0 +1,50 @@
/*
* 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.network.di
import com.google.samples.apps.nowinandroid.core.network.DefaultNiaDispatchers
import com.google.samples.apps.nowinandroid.core.network.NiANetwork
import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers
import com.google.samples.apps.nowinandroid.core.network.fake.FakeNiANetwork
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import kotlinx.serialization.json.Json
@Module
@InstallIn(SingletonComponent::class)
interface NetworkModule {
@Binds
fun bindsNiANetwork(
fakeNiANetwork: FakeNiANetwork
): NiANetwork
@Binds
fun bindsNiaDispatchers(defaultNiaDispatchers: DefaultNiaDispatchers): NiaDispatchers
companion object {
@Provides
@Singleton
fun providesNetworkJson(): Json = Json {
ignoreUnknownKeys = true
}
}
}

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.network.fake
import com.google.samples.apps.nowinandroid.data.network.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.model.network.NetworkTopic
import com.google.samples.apps.nowinandroid.data.network.NetworkTopic import com.google.samples.apps.nowinandroid.core.model.network.NetworkNewsResource
import kotlinx.datetime.LocalDateTime import kotlinx.datetime.LocalDateTime
import kotlinx.datetime.TimeZone import kotlinx.datetime.TimeZone
import kotlinx.datetime.toInstant import kotlinx.datetime.toInstant

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.network.fake
import com.google.samples.apps.nowinandroid.data.network.NetworkNewsResource import com.google.samples.apps.nowinandroid.core.model.network.NetworkNewsResource
import com.google.samples.apps.nowinandroid.data.network.NetworkTopic import com.google.samples.apps.nowinandroid.core.model.network.NetworkTopic
import com.google.samples.apps.nowinandroid.data.network.NiANetwork import com.google.samples.apps.nowinandroid.core.network.NiANetwork
import com.google.samples.apps.nowinandroid.di.NiaDispatchers import com.google.samples.apps.nowinandroid.core.network.NiaDispatchers
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

@ -14,9 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.data.fake package com.google.samples.apps.nowinandroid.core.network.fake
import com.google.samples.apps.nowinandroid.di.DefaultNiaDispatchers import com.google.samples.apps.nowinandroid.core.network.DefaultNiaDispatchers
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
@ -29,7 +29,7 @@ class FakeNiANetworkTest {
@Before @Before
fun setUp() { fun setUp() {
subject = FakeNiANetwork( subject = com.google.samples.apps.nowinandroid.core.network.fake.FakeNiANetwork(
// TODO: Create test-specific NiaDispatchers // TODO: Create test-specific NiaDispatchers
dispatchers = DefaultNiaDispatchers(), dispatchers = DefaultNiaDispatchers(),
networkJson = Json { ignoreUnknownKeys = true } networkJson = Json { ignoreUnknownKeys = true }

@ -0,0 +1 @@
/build

@ -0,0 +1,61 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation project(':core-domain')
implementation project(':core-model')
api libs.junit4
api libs.mockk
api libs.androidx.test.core
api libs.kotlinx.coroutines.test
api libs.turbine
api libs.androidx.test.espresso.core
api libs.androidx.test.runner
api libs.androidx.test.rules
api libs.androidx.compose.ui.test
api libs.hilt.android.testing
debugApi libs.androidx.compose.ui.testManifest
configurations.configureEach {
resolutionStrategy {
// Temporary workaround for https://issuetracker.google.com/174733673
force 'org.objenesis:objenesis:2.6'
}
}
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.testing">
</manifest>

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid package com.google.samples.apps.nowinandroid.core.testing
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.testutil package com.google.samples.apps.nowinandroid.core.testing.repository
import com.google.samples.apps.nowinandroid.data.model.NewsResource import com.google.samples.apps.nowinandroid.core.domain.repository.NewsRepository
import com.google.samples.apps.nowinandroid.data.repository.NewsRepository import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow

@ -14,10 +14,10 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.testutil package com.google.samples.apps.nowinandroid.core.testing.repository
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.domain.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.model.data.Topic
import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.MutableSharedFlow

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.testutil package com.google.samples.apps.nowinandroid.core.testing.util
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers

@ -0,0 +1 @@
/build

@ -0,0 +1,59 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion libs.versions.androidxCompose.get()
}
}
dependencies {
implementation project(':core-model')
implementation libs.androidx.core.ktx
implementation libs.kotlinx.datetime
api libs.androidx.compose.foundation.layout
// TODO (M3): Remove this dependency when all components are available
api libs.androidx.compose.material
api libs.androidx.compose.material.iconsExtended
api libs.androidx.compose.material3
debugApi libs.androidx.compose.ui.tooling
api libs.androidx.compose.ui.tooling.preview
api libs.androidx.compose.ui.util
api libs.androidx.compose.runtime
api libs.androidx.compose.runtime.livedata
}

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.core.ui">
</manifest>

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui package com.google.samples.apps.nowinandroid.core.ui
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
@ -36,17 +36,14 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.semantics.onClick import androidx.compose.ui.semantics.onClick
import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.core.model.data.NewsResource
import com.google.samples.apps.nowinandroid.data.fake.FakeDataSource import com.google.samples.apps.nowinandroid.core.model.entities.AuthorEntity
import com.google.samples.apps.nowinandroid.data.model.NewsResource import com.google.samples.apps.nowinandroid.core.model.entities.EpisodeEntity
import com.google.samples.apps.nowinandroid.data.network.NetworkAuthor import com.google.samples.apps.nowinandroid.core.model.entities.NewsResourceEntity
import com.google.samples.apps.nowinandroid.data.network.NetworkEpisode import com.google.samples.apps.nowinandroid.core.model.entities.TopicEntity
import com.google.samples.apps.nowinandroid.data.network.NetworkTopic import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme
import com.google.samples.apps.nowinandroid.data.network.asEntity import kotlinx.datetime.Instant
import com.google.samples.apps.nowinandroid.ui.theme.NiaTheme
/** /**
* [NewsResource] card used on the following screens: For You, Episodes, Saved * [NewsResource] card used on the following screens: For You, Episodes, Saved
@ -166,10 +163,9 @@ fun BookmarkButtonBookmarkedPreview() {
} }
} }
@Preview("NewsResourceCardExpanded")
@Composable @Composable
fun ExpandedNewsResourcePreview( fun ExpandedNewsResourcePreview() {
@PreviewParameter(NewsResourcePreviewParameterProvider::class) newsResource: NewsResource
) {
NiaTheme { NiaTheme {
Surface { Surface {
NewsResourceCardExpanded(newsResource, true, {}) NewsResourceCardExpanded(newsResource, true, {})
@ -177,32 +173,36 @@ fun ExpandedNewsResourcePreview(
} }
} }
class NewsResourcePreviewParameterProvider : PreviewParameterProvider<NewsResource> { private val newsResource = NewsResource(
override val values = sequenceOf( NewsResourceEntity(
NewsResource( id = 1,
FakeDataSource.sampleResource.asEntity(), episodeId = 1,
NetworkEpisode( title = "Title",
id = 1, content = "Content",
name = "Now in Android 40", url = "url",
alternateVideo = null, publishDate = Instant.DISTANT_FUTURE,
alternateAudio = null, type = "type",
publishDate = FakeDataSource.sampleResource.publishDate ),
).asEntity(), EpisodeEntity(
listOf( id = 1,
NetworkAuthor( name = "Title",
id = 1, publishDate = Instant.DISTANT_FUTURE,
name = "Android", alternateVideo = "alternateVideo",
imageUrl = "" alternateAudio = "alternateAudio",
) ),
.asEntity() listOf(
), AuthorEntity(
listOf( id = 1,
NetworkTopic( name = "Name",
id = 3, imageUrl = "imageUrl"
name = "Performance", )
description = "" ),
).asEntity() listOf(
) TopicEntity(
id = 1,
name = "Name",
description = "Description",
followed = false
) )
) )
} )

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui package com.google.samples.apps.nowinandroid.core.ui
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.theme package com.google.samples.apps.nowinandroid.core.ui.theme
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.theme package com.google.samples.apps.nowinandroid.core.ui.theme
import android.os.Build import android.os.Build
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.theme package com.google.samples.apps.nowinandroid.core.ui.theme
import androidx.compose.material3.Typography import androidx.compose.material3.Typography

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2021 Google LLC
~
~ 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.
-->
<resources>
<string name="bookmark">Bookmark</string>
<string name="unbookmark">Unbookmark</string>
</resources>

@ -0,0 +1 @@
/build

@ -0,0 +1,71 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
testInstrumentationRunner "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion libs.versions.androidxCompose.get()
}
}
dependencies {
implementation project(':core-model')
implementation project(':core-ui')
implementation project(':core-domain')
testImplementation project(':core-testing')
androidTestImplementation project(':core-testing')
implementation libs.kotlinx.coroutines.android
implementation libs.androidx.hilt.navigation.compose
implementation libs.androidx.lifecycle.viewModelCompose
implementation libs.hilt.android
kapt libs.hilt.compiler
// 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'
}
}
}

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.following package com.google.samples.apps.nowinandroid.following
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertCountEquals import androidx.compose.ui.test.assertCountEquals
@ -24,8 +24,10 @@ import androidx.compose.ui.test.onAllNodesWithContentDescription
import androidx.compose.ui.test.onAllNodesWithText import androidx.compose.ui.test.onAllNodesWithText
import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.feature.following.FollowingScreen
import com.google.samples.apps.nowinandroid.feature.following.FollowingUiState
import com.google.samples.apps.nowinandroid.feature.following.R
import org.junit.Before import org.junit.Before
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.feature.following">
</manifest>

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.following package com.google.samples.apps.nowinandroid.feature.following
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
@ -45,11 +45,10 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.ui.NiaLoadingIndicator
import com.google.samples.apps.nowinandroid.ui.NiaLoadingIndicator import com.google.samples.apps.nowinandroid.core.ui.NiaToolbar
import com.google.samples.apps.nowinandroid.ui.NiaToolbar import com.google.samples.apps.nowinandroid.core.ui.theme.NiaTheme
import com.google.samples.apps.nowinandroid.ui.theme.NiaTheme
@Composable @Composable
fun FollowingRoute( fun FollowingRoute(

@ -14,12 +14,12 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.following package com.google.samples.apps.nowinandroid.feature.following
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.domain.repository.TopicsRepository
import com.google.samples.apps.nowinandroid.data.repository.TopicsRepository import com.google.samples.apps.nowinandroid.core.model.data.Topic
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright 2022 Google LLC
~
~ 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.
-->
<resources>
<string name="following">Following</string>
<string name="following_loading">Loading topics</string>
<string name="following_error_header">"Error loading topics"</string>
<string name="following_topic_card_icon_content_desc">Topic icon</string>
<string name="following_topic_card_follow_button_content_desc">Follow Topic button</string>
<string name="following_topic_card_unfollow_button_content_desc">Unfollow Topic button</string>
</resources>

@ -14,12 +14,14 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.following package com.google.samples.apps.nowinandroid.following
import app.cash.turbine.test import app.cash.turbine.test
import com.google.samples.apps.nowinandroid.data.model.Topic import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.testutil.TestDispatcherRule import com.google.samples.apps.nowinandroid.core.testing.repository.TestTopicsRepository
import com.google.samples.apps.nowinandroid.testutil.TestTopicsRepository import com.google.samples.apps.nowinandroid.core.testing.util.TestDispatcherRule
import com.google.samples.apps.nowinandroid.feature.following.FollowingUiState
import com.google.samples.apps.nowinandroid.feature.following.FollowingViewModel
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Before import org.junit.Before

@ -0,0 +1 @@
/build

@ -0,0 +1,73 @@
/*
* 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.
*/
plugins {
id 'com.android.library'
id 'kotlin-android'
id 'kotlin-kapt'
id 'dagger.hilt.android.plugin'
}
android {
compileSdk buildConfig.compileSdk
defaultConfig {
minSdk buildConfig.minSdk
targetSdk buildConfig.targetSdk
testInstrumentationRunner "com.google.samples.apps.nowinandroid.core.testing.NiaTestRunner"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion libs.versions.androidxCompose.get()
}
}
dependencies {
implementation project(':core-model')
implementation project(':core-ui')
implementation project(':core-domain')
testImplementation project(':core-testing')
androidTestImplementation project(':core-testing')
implementation libs.kotlinx.coroutines.android
implementation libs.androidx.hilt.navigation.compose
implementation libs.androidx.lifecycle.viewModelCompose
implementation libs.accompanist.flowlayout
implementation libs.hilt.android
kapt libs.hilt.compiler
// 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'
}
}
}

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.samples.apps.nowinandroid.ui.foryou package com.google.samples.apps.nowinandroid.feature.foryou
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.compose.ui.test.assertHasClickAction import androidx.compose.ui.test.assertHasClickAction
@ -26,8 +26,7 @@ import androidx.compose.ui.test.assertIsOn
import androidx.compose.ui.test.junit4.createAndroidComposeRule import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithContentDescription import androidx.compose.ui.test.onNodeWithContentDescription
import androidx.compose.ui.test.onNodeWithText import androidx.compose.ui.test.onNodeWithText
import com.google.samples.apps.nowinandroid.R import com.google.samples.apps.nowinandroid.core.model.data.Topic
import com.google.samples.apps.nowinandroid.data.model.Topic
import org.junit.Rule import org.junit.Rule
import org.junit.Test import org.junit.Test

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.samples.apps.nowinandroid.feature.foryou">
</manifest>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save