From e7aff81c7b8126cd92c1eacce39973f56b53d97f Mon Sep 17 00:00:00 2001 From: Kaushal-Vasava Date: Mon, 16 Jan 2023 18:30:02 +0530 Subject: [PATCH 1/4] Add News app code - Add retrofit, coil, viewmodel dependencies - Add news related code --- app/build.gradle | 12 ++- app/src/main/AndroidManifest.xml | 1 + .../apps/jetpackcomposebasic/MainActivity.kt | 75 +++++++++++++++--- .../apps/jetpackcomposebasic/api/ApiClient.kt | 16 ++++ .../apps/jetpackcomposebasic/api/NewApi.kt | 20 +++++ .../apps/jetpackcomposebasic/model/News.kt | 8 ++ .../model/NewsParentModel.kt | 7 ++ .../repo/NewsRepository.kt | 14 ++++ .../apps/jetpackcomposebasic/ui/NewsItem.kt | 77 +++++++++++++++++++ .../jetpackcomposebasic/ui/theme/Color.kt | 3 +- .../ui/viewmodel/NewsViewModel.kt | 26 +++++++ 11 files changed, 247 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/ApiClient.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/NewsParentModel.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt diff --git a/app/build.gradle b/app/build.gradle index 75677b5..18d9905 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,6 +37,7 @@ android { compose true } composeOptions { + kotlinCompilerExtensionVersion '1.1.1' } packagingOptions { @@ -53,11 +54,20 @@ dependencies { implementation 'androidx.activity:activity-compose:1.6.1' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" - implementation 'androidx.compose.material3:material3:1.1.0-alpha03' + implementation 'androidx.compose.material3:material3:1.0.1' + + implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1" + //retrofit + implementation 'com.squareup.retrofit2:retrofit:2.9.0' + implementation "com.squareup.retrofit2:converter-gson:2.9.0" + //coil + implementation("io.coil-kt:coil-compose:2.2.2") + testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.4' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ebfd06..f74e623 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,7 @@ + { + val list = mutableListOf() + for (i in 0..10) { + list.add( + News( + "Kaushal", + "Ness", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + ) + ) + } + return list +} + +@Composable +fun getNewsData( + modifier: Modifier, + newsViewModel: NewsViewModel +) { + val newsList by newsViewModel.newsFlow.collectAsState() +// val d = getList() + LazyColumn(modifier = modifier.padding(vertical = 4.dp)) { + items(items = newsList) { news -> + NewsItem(news = news) + } + } +} + @Composable fun Greeting(name: String) { Text(text = "Hello $name!") @@ -45,6 +92,14 @@ fun Greeting(name: String) { @Composable fun DefaultPreview() { JetPackComposeBasicTheme { - Greeting("Android") + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + RadioButtonUI() + CheckBoxUI("Accept term and condition") + EditTextUI("Enter your name", modifier = Modifier.fillMaxWidth()) + PasswordFieldUI("Enter your password", modifier = Modifier.fillMaxWidth()) + } } } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/ApiClient.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/ApiClient.kt new file mode 100644 index 0000000..47576d0 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/ApiClient.kt @@ -0,0 +1,16 @@ +package com.lahsuak.apps.jetpackcomposebasic.api + +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +object ApiClient { + val apiInterface: NewApi by lazy { + Retrofit.Builder() + .baseUrl(NewApi.BASE_URL) + .addConverterFactory( + GsonConverterFactory.create() + ) + .build() + .create(NewApi::class.java) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt new file mode 100644 index 0000000..85fd3ad --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt @@ -0,0 +1,20 @@ +package com.lahsuak.apps.jetpackcomposebasic.api + +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.model.NewsParentModel +import retrofit2.http.GET +import retrofit2.http.Path +import retrofit2.http.Query + + +interface NewApi { + companion object { + const val BASE_URL = "https://saurav.tech"//NewsAPI/top-headlines/category/general/in.json" + } + + @GET("/NewsAPI/top-headlines/category/general/in.json") + suspend fun getNews( +// @Path("category") +// category: String + ): NewsParentModel +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt new file mode 100644 index 0000000..f6b78ba --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt @@ -0,0 +1,8 @@ +package com.lahsuak.apps.jetpackcomposebasic.model + +data class News ( + val description:String, + val title:String, + val url:String, + val urlToImage:String, +) diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/NewsParentModel.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/NewsParentModel.kt new file mode 100644 index 0000000..d829b71 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/NewsParentModel.kt @@ -0,0 +1,7 @@ +package com.lahsuak.apps.jetpackcomposebasic.model + +data class NewsParentModel( + val status: String, + val totalResults: Int, + val articles: List +) \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt new file mode 100644 index 0000000..f47094d --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt @@ -0,0 +1,14 @@ +package com.lahsuak.apps.jetpackcomposebasic.repo + +import com.lahsuak.apps.jetpackcomposebasic.api.ApiClient +import com.lahsuak.apps.jetpackcomposebasic.api.NewApi +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.model.NewsParentModel + +class NewsRepository(private val apiInterface: NewApi= ApiClient.apiInterface) { + suspend fun getNews(category: String): NewsParentModel { + return apiInterface.getNews( +// category + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt new file mode 100644 index 0000000..7e65148 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt @@ -0,0 +1,77 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui + +import androidx.compose.foundation.Image +import androidx.compose.foundation.layout.* +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.unit.dp +import coil.compose.rememberAsyncImagePainter +import coil.request.ImageRequest +import com.lahsuak.apps.jetpackcomposebasic.R +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme + +@Composable +fun NewsItem(news: News) { + val painter = rememberAsyncImagePainter( + model = ImageRequest.Builder(LocalContext.current) + .data(news.urlToImage) + .placeholder(R.drawable.ic_launcher_foreground) + .crossfade(true) + .build(), + contentScale = ContentScale.FillWidth + ) + Column(modifier = Modifier.fillMaxWidth()) { + Image( + painter = painter, + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .height(200.dp), + ) + Text( + text = news.title, + style = MaterialTheme.typography.bodyMedium, + maxLines = 1, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) + ) + Text( + text = news.description, + style = MaterialTheme.typography.bodySmall, + maxLines = 3, + overflow = TextOverflow.Ellipsis, + color = Color.Gray, + modifier = Modifier.padding(horizontal = 8.dp) + ) + } +} + + +@Preview +@Composable +fun NewsItemPreview() { + JetPackComposeBasicTheme { + // A surface container using the 'background' color from the theme + Surface( + modifier = Modifier.fillMaxSize(), + color = MaterialTheme.colorScheme.background + ) { + NewsItem( + news = News( + "Kaushal", + "Ness", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + ) + ) + } + } +} diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/theme/Color.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/theme/Color.kt index e0a4930..c45f5f8 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/theme/Color.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/theme/Color.kt @@ -8,4 +8,5 @@ val Pink80 = Color(0xFFEFB8C8) val Purple40 = Color(0xFF6650a4) val PurpleGrey40 = Color(0xFF625b71) -val Pink40 = Color(0xFF7D5260) \ No newline at end of file +val Pink40 = Color(0xFF7D5260) +val Grey = Color(0xFF534F50) \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt new file mode 100644 index 0000000..ad78a0c --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt @@ -0,0 +1,26 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.repo.NewsRepository +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.launch + +class NewsViewModel : ViewModel() { + private val _newsFlow: MutableStateFlow> = MutableStateFlow(emptyList()) + val newsFlow: StateFlow> + get() = _newsFlow + + private val newsRepo: NewsRepository by lazy { + NewsRepository() + } + + fun getNews(category: String) { + viewModelScope.launch { + val newsParentModel = newsRepo.getNews(category) + _newsFlow.value = newsParentModel.articles + } + } +} From 9564b3d05fd9077f95ee98758911483183dc5424 Mon Sep 17 00:00:00 2001 From: Kaushal-Vasava Date: Tue, 17 Jan 2023 12:52:34 +0530 Subject: [PATCH 2/4] Add navigation graph and navigation code - Add android browser library from custom crome tab --- app/build.gradle | 7 ++ .../apps/jetpackcomposebasic/MainActivity.kt | 68 +----------------- .../apps/jetpackcomposebasic/api/NewApi.kt | 7 ++ .../apps/jetpackcomposebasic/model/News.kt | 16 +++-- .../apps/jetpackcomposebasic/ui/CromeTab.kt | 15 ++++ .../apps/jetpackcomposebasic/ui/Helper.kt | 16 +++++ .../apps/jetpackcomposebasic/ui/NavHost.kt | 39 ++++++++++ .../jetpackcomposebasic/ui/NavigationItem.kt | 6 ++ .../apps/jetpackcomposebasic/ui/NewsItem.kt | 10 ++- .../ui/detailscreen/Detailscreen.kt | 16 +++++ .../jetpackcomposebasic/ui/home/HomeScreen.kt | 49 +++++++++++++ .../apps/jetpackcomposebasic/NewsApiTest.kt | 72 +++++++++++++++++++ app/src/test/resources/test.json | 32 +++++++++ 13 files changed, 279 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt create mode 100644 app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt create mode 100644 app/src/test/resources/test.json diff --git a/app/build.gradle b/app/build.gradle index 18d9905..12ac8b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,6 +1,7 @@ plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' + id 'kotlin-parcelize' } android { @@ -70,4 +71,10 @@ dependencies { debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" + implementation "androidx.navigation:navigation-compose:2.5.3" + implementation 'androidx.browser:browser:1.4.0' + + testImplementation 'com.squareup.okhttp3:mockwebserver:4.9.0' + testImplementation 'org.mockito:mockito-core:2.23.0' + testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0' } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt index 35f7bf8..08de62e 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt @@ -3,28 +3,14 @@ package com.lahsuak.apps.jetpackcomposebasic import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent -import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface -import androidx.compose.material3.Text import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import androidx.compose.ui.unit.dp -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewmodel.compose.viewModel -import com.lahsuak.apps.jetpackcomposebasic.model.News -import com.lahsuak.apps.jetpackcomposebasic.ui.NewsItem -import com.lahsuak.apps.jetpackcomposebasic.ui.elements.* +import com.lahsuak.apps.jetpackcomposebasic.ui.MyAppNavHost import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme -import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -36,58 +22,13 @@ class MainActivity : ComponentActivity() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - val newsViewModel: NewsViewModel = viewModel() - newsViewModel.getNews("general") - getNewsData(modifier = Modifier.fillMaxSize(), newsViewModel) -// Column(Modifier.padding(vertical = 16.dp, horizontal = 8.dp)) { -// RadioButtonUI() -// CheckBoxUI("Accept term and condition") -// EditTextUI("Enter your name", modifier = Modifier.fillMaxWidth()) -// PasswordFieldUI("Enter your password", modifier = Modifier.fillMaxWidth()) -// Search(placeHolderMsg = "Search", modifier = Modifier.fillMaxWidth()) -// SnackBarUI("Hello it's me snackbar") -// } + MyAppNavHost() } } } } } -@Composable -fun getList(): List { - val list = mutableListOf() - for (i in 0..10) { - list.add( - News( - "Kaushal", - "Ness", - "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", - "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", - ) - ) - } - return list -} - -@Composable -fun getNewsData( - modifier: Modifier, - newsViewModel: NewsViewModel -) { - val newsList by newsViewModel.newsFlow.collectAsState() -// val d = getList() - LazyColumn(modifier = modifier.padding(vertical = 4.dp)) { - items(items = newsList) { news -> - NewsItem(news = news) - } - } -} - -@Composable -fun Greeting(name: String) { - Text(text = "Hello $name!") -} - @Preview(showBackground = true) @Composable fun DefaultPreview() { @@ -96,10 +37,7 @@ fun DefaultPreview() { modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background ) { - RadioButtonUI() - CheckBoxUI("Accept term and condition") - EditTextUI("Enter your name", modifier = Modifier.fillMaxWidth()) - PasswordFieldUI("Enter your password", modifier = Modifier.fillMaxWidth()) + MyAppNavHost() } } } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt index 85fd3ad..680383f 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt @@ -2,6 +2,7 @@ package com.lahsuak.apps.jetpackcomposebasic.api import com.lahsuak.apps.jetpackcomposebasic.model.News import com.lahsuak.apps.jetpackcomposebasic.model.NewsParentModel +import retrofit2.Response import retrofit2.http.GET import retrofit2.http.Path import retrofit2.http.Query @@ -17,4 +18,10 @@ interface NewApi { // @Path("category") // category: String ): NewsParentModel + + @GET("/NewsAPI/top-headlines/category/general/in.json") + suspend fun getNews2( +// @Path("category") +// category: String + ): Response } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt index f6b78ba..60aa2e8 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/model/News.kt @@ -1,8 +1,12 @@ package com.lahsuak.apps.jetpackcomposebasic.model -data class News ( - val description:String, - val title:String, - val url:String, - val urlToImage:String, -) +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class News( + val description: String, + val title: String, + val url: String, + val urlToImage: String, +) : Parcelable diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt new file mode 100644 index 0000000..42b9c11 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt @@ -0,0 +1,15 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui + +import android.content.Context +import android.net.Uri +import androidx.browser.customtabs.CustomTabsIntent + +fun openTab(context: Context, url: String) { + val packageName = "com.android.chrome" + val builder = CustomTabsIntent.Builder() + builder.setShowTitle(true) + builder.setInstantAppsEnabled(true) + val customBuilder = builder.build() + customBuilder.intent.setPackage(packageName) + customBuilder.launchUrl(context, Uri.parse(url)) +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt new file mode 100644 index 0000000..80d01e8 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt @@ -0,0 +1,16 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui + +import java.io.InputStreamReader + +object Helper { + fun readFileResource(fileName: String): String{ + val inputStream = Helper::class.java.getResourceAsStream(fileName) + val builder = StringBuilder() + val reader = InputStreamReader(inputStream,Charsets.UTF_8) + reader.readLines().forEach{ + builder.append(it) + } + return builder.toString() + } +} + diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt new file mode 100644 index 0000000..4316a48 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt @@ -0,0 +1,39 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui + +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.lifecycle.viewmodel.compose.viewModel +import androidx.navigation.NavHostController +import androidx.navigation.compose.NavHost +import androidx.navigation.compose.composable +import androidx.navigation.compose.rememberNavController +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.ui.detailscreen.DetailScreen +import com.lahsuak.apps.jetpackcomposebasic.ui.home.HomeScreen +import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel + +@Composable +fun MyAppNavHost( + modifier: Modifier = Modifier, + navController: NavHostController = rememberNavController(), + startDestination: String = NavigationItem.Home.route +) { + NavHost( + modifier = modifier, + navController = navController, + startDestination = startDestination + ) { + composable(NavigationItem.Home.route) { + val newsViewModel: NewsViewModel = viewModel() + newsViewModel.getNews("general") + HomeScreen( + navController, newsViewModel + ) + } + composable(NavigationItem.Details.route) { + val news = + navController.previousBackStackEntry?.savedStateHandle?.get("news") + DetailScreen(text = news?.url?:"") + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt new file mode 100644 index 0000000..43e251f --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt @@ -0,0 +1,6 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui + +sealed class NavigationItem(val route: String) { + object Home : NavigationItem("home") + object Details : NavigationItem("details") +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt index 7e65148..e2760c7 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt @@ -1,6 +1,7 @@ package com.lahsuak.apps.jetpackcomposebasic.ui import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.* import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface @@ -13,6 +14,7 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp +import androidx.navigation.NavController import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest import com.lahsuak.apps.jetpackcomposebasic.R @@ -20,7 +22,7 @@ import com.lahsuak.apps.jetpackcomposebasic.model.News import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme @Composable -fun NewsItem(news: News) { +fun NewsItem(news: News, onClick: () -> Unit) { val painter = rememberAsyncImagePainter( model = ImageRequest.Builder(LocalContext.current) .data(news.urlToImage) @@ -29,7 +31,9 @@ fun NewsItem(news: News) { .build(), contentScale = ContentScale.FillWidth ) - Column(modifier = Modifier.fillMaxWidth()) { + Column(modifier = Modifier.fillMaxWidth().clickable { + onClick() + }) { Image( painter = painter, contentDescription = null, @@ -71,7 +75,7 @@ fun NewsItemPreview() { "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", ) - ) + ) {} } } } diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt new file mode 100644 index 0000000..dab26bb --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt @@ -0,0 +1,16 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.detailscreen + +import androidx.compose.foundation.clickable +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import com.lahsuak.apps.jetpackcomposebasic.ui.openTab + +@Composable +fun DetailScreen(text: String) { + val context = LocalContext.current + Text(text = text, Modifier.clickable { + openTab(context, text) + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt new file mode 100644 index 0000000..403e280 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt @@ -0,0 +1,49 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.home + +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.navigation.NavController +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.ui.NewsItem +import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel + +@Composable +fun HomeScreen( + navController: NavController, + newsViewModel: NewsViewModel +) { + + val newsList by newsViewModel.newsFlow.collectAsState() + LazyColumn(modifier = Modifier.padding(vertical = 4.dp)) { + items(items = newsList) { news -> + NewsItem( + news = news, + ) { + navController.currentBackStackEntry?.savedStateHandle?.set("news", news) + navController.navigate("details") + } + } + } +} + +@Composable +fun getList(): List { + val list = mutableListOf() + for (i in 0..10) { + list.add( + News( + "Kaushal", + "Ness", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", + ) + ) + } + return list +} \ No newline at end of file diff --git a/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt b/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt new file mode 100644 index 0000000..68091df --- /dev/null +++ b/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt @@ -0,0 +1,72 @@ +package com.lahsuak.apps.jetpackcomposebasic + +import com.lahsuak.apps.jetpackcomposebasic.api.NewApi +import com.lahsuak.apps.jetpackcomposebasic.ui.Helper +import kotlinx.coroutines.runBlocking +import okhttp3.mockwebserver.MockResponse +import okhttp3.mockwebserver.MockWebServer +import org.junit.After +import org.junit.Assert +import org.junit.Before +import org.junit.Test +import retrofit2.Retrofit +import retrofit2.converter.gson.GsonConverterFactory + +class NewsApiTest { + + lateinit var mockWebServer: MockWebServer + lateinit var newApi: NewApi + + @Before + fun setUp() { + mockWebServer = MockWebServer() + newApi = Retrofit.Builder() + .baseUrl(mockWebServer.url("/")) + .addConverterFactory(GsonConverterFactory.create()) + .build().create(NewApi::class.java) + } + + @Test + fun testGetNews_ReturnEmptyResponse() = runBlocking { + val mockResponse = MockResponse() + mockResponse.setBody("{}") + mockWebServer.enqueue(mockResponse) + + val response = newApi.getNews() + mockWebServer.takeRequest() + Assert.assertEquals(null, response.articles) + } + + @Test + fun testGetNews_returnNews() = runBlocking { + val mockResponse = MockResponse() + val content = Helper.readFileResource("/test.json") + mockResponse.setResponseCode(200) + mockResponse.setBody(content) + mockWebServer.enqueue(mockResponse) + + val response = newApi.getNews() + mockWebServer.takeRequest() + Assert.assertEquals(true, response.articles.isNotEmpty()) + Assert.assertEquals(2, response.articles.size) + } + + @Test + fun testGetNews_returnError() = runBlocking { + val mockResponse = MockResponse() + mockResponse.setResponseCode(404) + mockResponse.setBody("Something went wrong!") + mockWebServer.enqueue(mockResponse) + + val response = newApi.getNews2() + mockWebServer.takeRequest() + Assert.assertEquals(true, response.isSuccessful) + Assert.assertEquals(404, response.code()) + } + + + @After + fun tearDown() { + mockWebServer.shutdown() + } +} diff --git a/app/src/test/resources/test.json b/app/src/test/resources/test.json new file mode 100644 index 0000000..4698474 --- /dev/null +++ b/app/src/test/resources/test.json @@ -0,0 +1,32 @@ +{ + "status": "ok", + "totalResults": 35, + "articles": [ + { + "source": { + "id": null, + "name": "CNBCTV18" + }, + "author": "CNBCTV18.com", + "title": "Stock Market Live News Updates: Sensex live today Nifty50 live today Nestle HCL Tech Larsen Toubro Tech Russia - CNBCTV18", + "description": "Stock Market Highlights: Indian equity benchmarks BSE Sensex and NSE Nifty50 continued to rise for a second straight day on Thursday led by gains across IT stocks and heavyweights Reliance Industries, Infosys and the HDFC twins. Broader markets also strengthe\u2026", + "url": "https://www.cnbctv18.com/market/stocks/stock-market-news-live-updates-nifty50-bse-sensex-hcl-tech-nestle-lt-tech-tata-elxsi-brent-crude-bitcoin-gold-price-13222162.htm", + "urlToImage": "https://images.cnbctv18.com/wp-content/uploads/2019/07/BSE-Sensex.jpg", + "publishedAt": "2022-04-21T12:17:49Z", + "content": "Why Saurabh\u00a0Mukherjea likes HDFC Bank \r\nSaurabh Mukherjea, Founder at Marcellus Investment Managers, says in an interview to CNBC-TV18 that HDFC Bank's delivery over the past three, five, 10 or even \u2026 [+1086 chars]" + }, + { + "source": { + "id": null, + "name": "NDTV News" + }, + "author": null, + "title": "Sachin Pilot Meets Sonia Gandhi Over His Future Role In Congress: Sources - NDTV", + "description": "Rajasthan Congress leader Sachin Pilot met with Sonia Gandhi today amid reports that he has expressed his fervent wish to become Chief Minister.", + "url": "https://www.ndtv.com/india-news/sachin-pilot-meets-sonia-gandhi-over-his-future-role-in-congress-sources-2907424", + "urlToImage": "https://c.ndtvimg.com/2021-10/an9r19h4_sachin-pilot-pti-photo_625x300_06_October_21.jpg", + "publishedAt": "2022-04-21T12:03:22Z", + "content": "The political call on Sonia Gandhi's role will be taken by Sonia Gandhi. (FILE)\r\nNew Delhi: Rajasthan Congress leader Sachin Pilot met with Sonia Gandhi today amid reports that he has expressed his f\u2026 [+1845 chars]" + } + ] +} \ No newline at end of file From ac35d19e70b4600c765b012575e6cef6b4f418b0 Mon Sep 17 00:00:00 2001 From: KaushalVasava Date: Thu, 20 Jul 2023 18:30:22 +0530 Subject: [PATCH 3/4] Update news app - Update dependencies - Update News details screen - Update News item - Add Category model - Add filter chips --- app/build.gradle | 28 +++--- .../apps/jetpackcomposebasic/MainActivity.kt | 2 +- .../apps/jetpackcomposebasic/api/NewApi.kt | 6 +- .../repo/NewsRepository.kt | 2 +- .../apps/jetpackcomposebasic/ui/CromeTab.kt | 15 --- .../apps/jetpackcomposebasic/ui/Helper.kt | 16 ---- .../jetpackcomposebasic/ui/NavigationItem.kt | 6 -- .../ui/components/ChipGroup.kt | 54 +++++++++++ .../ui/{ => components}/NewsItem.kt | 65 +++++++------ .../ui/components/model/Category.kt | 10 ++ .../ui/components/model/CategoryType.kt | 7 ++ .../ui/detailscreen/Detailscreen.kt | 16 ---- .../jetpackcomposebasic/ui/home/HomeScreen.kt | 49 ---------- .../ui/{ => navigation}/NavHost.kt | 24 ++--- .../ui/navigation/NavigationItem.kt | 10 ++ .../ui/screen/detailscreen/Detailscreen.kt | 94 +++++++++++++++++++ .../ui/screen/home/HomeScreen.kt | 60 ++++++++++++ .../ui/viewmodel/NewsViewModel.kt | 5 + .../apps/jetpackcomposebasic/util/AppUtil.kt | 29 ++++++ app/src/main/res/values/strings.xml | 2 + .../apps/jetpackcomposebasic/NewsApiTest.kt | 8 +- build.gradle | 8 +- 22 files changed, 348 insertions(+), 168 deletions(-) delete mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt delete mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt delete mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/ChipGroup.kt rename app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/{ => components}/NewsItem.kt (59%) create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/Category.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/CategoryType.kt delete mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt delete mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt rename app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/{ => navigation}/NavHost.kt (60%) create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavigationItem.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/detailscreen/Detailscreen.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/home/HomeScreen.kt create mode 100644 app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/util/AppUtil.kt diff --git a/app/build.gradle b/app/build.gradle index 12ac8b9..3e8e664 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -28,18 +28,18 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { - jvmTarget = '1.8' + jvmTarget = '17' } buildFeatures { compose true } composeOptions { - kotlinCompilerExtensionVersion '1.1.1' + kotlinCompilerExtensionVersion '1.4.0' } packagingOptions { resources { @@ -50,14 +50,14 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.9.0' - implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1' - implementation 'androidx.activity:activity-compose:1.6.1' + implementation 'androidx.core:core-ktx:1.10.1' + implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1' + implementation 'androidx.activity:activity-compose:1.7.2' implementation "androidx.compose.ui:ui:$compose_version" implementation "androidx.compose.ui:ui-tooling-preview:$compose_version" - implementation 'androidx.compose.material3:material3:1.0.1' + implementation 'androidx.compose.material3:material3:1.1.1' - implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1" + implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1" //retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation "com.squareup.retrofit2:converter-gson:2.9.0" @@ -65,16 +65,16 @@ dependencies { implementation("io.coil-kt:coil-compose:2.2.2") testImplementation 'junit:junit:4.13.2' - androidTestImplementation 'androidx.test.ext:junit:1.1.4' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0' + androidTestImplementation 'androidx.test.ext:junit:1.1.5' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version" debugImplementation "androidx.compose.ui:ui-tooling:$compose_version" debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version" - implementation "androidx.navigation:navigation-compose:2.5.3" - implementation 'androidx.browser:browser:1.4.0' + implementation "androidx.navigation:navigation-compose:2.6.0" + implementation 'androidx.browser:browser:1.5.0' testImplementation 'com.squareup.okhttp3:mockwebserver:4.9.0' - testImplementation 'org.mockito:mockito-core:2.23.0' + testImplementation 'org.mockito:mockito-core:2.25.0' testImplementation 'com.nhaarman.mockitokotlin2:mockito-kotlin:2.2.0' } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt index 08de62e..c55f762 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/MainActivity.kt @@ -9,7 +9,7 @@ import androidx.compose.material3.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview -import com.lahsuak.apps.jetpackcomposebasic.ui.MyAppNavHost +import com.lahsuak.apps.jetpackcomposebasic.ui.navigation.MyAppNavHost import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme class MainActivity : ComponentActivity() { diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt index 680383f..6393535 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/api/NewApi.kt @@ -13,10 +13,10 @@ interface NewApi { const val BASE_URL = "https://saurav.tech"//NewsAPI/top-headlines/category/general/in.json" } - @GET("/NewsAPI/top-headlines/category/general/in.json") + @GET("/NewsAPI/top-headlines/category/{category}/in.json") suspend fun getNews( -// @Path("category") -// category: String + @Path("category") + category: String ): NewsParentModel @GET("/NewsAPI/top-headlines/category/general/in.json") diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt index f47094d..0fb21e6 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/repo/NewsRepository.kt @@ -8,7 +8,7 @@ import com.lahsuak.apps.jetpackcomposebasic.model.NewsParentModel class NewsRepository(private val apiInterface: NewApi= ApiClient.apiInterface) { suspend fun getNews(category: String): NewsParentModel { return apiInterface.getNews( -// category + category ) } } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt deleted file mode 100644 index 42b9c11..0000000 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/CromeTab.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui - -import android.content.Context -import android.net.Uri -import androidx.browser.customtabs.CustomTabsIntent - -fun openTab(context: Context, url: String) { - val packageName = "com.android.chrome" - val builder = CustomTabsIntent.Builder() - builder.setShowTitle(true) - builder.setInstantAppsEnabled(true) - val customBuilder = builder.build() - customBuilder.intent.setPackage(packageName) - customBuilder.launchUrl(context, Uri.parse(url)) -} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt deleted file mode 100644 index 80d01e8..0000000 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/Helper.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui - -import java.io.InputStreamReader - -object Helper { - fun readFileResource(fileName: String): String{ - val inputStream = Helper::class.java.getResourceAsStream(fileName) - val builder = StringBuilder() - val reader = InputStreamReader(inputStream,Charsets.UTF_8) - reader.readLines().forEach{ - builder.append(it) - } - return builder.toString() - } -} - diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt deleted file mode 100644 index 43e251f..0000000 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavigationItem.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui - -sealed class NavigationItem(val route: String) { - object Home : NavigationItem("home") - object Details : NavigationItem("details") -} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/ChipGroup.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/ChipGroup.kt new file mode 100644 index 0000000..2ba0699 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/ChipGroup.kt @@ -0,0 +1,54 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.components + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyRow +import androidx.compose.foundation.lazy.items +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.List +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.FilterChip +import androidx.compose.material3.Icon +import androidx.compose.material3.IconButton +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import com.lahsuak.apps.jetpackcomposebasic.R +import com.lahsuak.apps.jetpackcomposebasic.ui.components.model.Category + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun ChipGroup( + categories: List, + selectedCategory: Category, + onSelectedChanged: (Category) -> Unit = {}, +) { + Column(modifier = Modifier.padding(8.dp)) { + LazyRow { + item { + IconButton( + onClick = { /* no-op */ } + ) { + Icon( + imageVector = Icons.Default.List, + contentDescription = stringResource(R.string.label_filters) + ) + } + } + items(categories) { + FilterChip( + label = { + Text(it.name.uppercase()) + }, + modifier = Modifier.padding(horizontal = 4.dp), + selected = selectedCategory == it, + onClick = { + onSelectedChanged(it) + }, + ) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/NewsItem.kt similarity index 59% rename from app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt rename to app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/NewsItem.kt index e2760c7..6a64714 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NewsItem.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/NewsItem.kt @@ -1,8 +1,13 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui +package com.lahsuak.apps.jetpackcomposebasic.ui.components import androidx.compose.foundation.Image import androidx.compose.foundation.clickable -import androidx.compose.foundation.layout.* +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Card import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface import androidx.compose.material3.Text @@ -14,7 +19,6 @@ import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp -import androidx.navigation.NavController import coil.compose.rememberAsyncImagePainter import coil.request.ImageRequest import com.lahsuak.apps.jetpackcomposebasic.R @@ -23,6 +27,7 @@ import com.lahsuak.apps.jetpackcomposebasic.ui.theme.JetPackComposeBasicTheme @Composable fun NewsItem(news: News, onClick: () -> Unit) { + // coil image painter val painter = rememberAsyncImagePainter( model = ImageRequest.Builder(LocalContext.current) .data(news.urlToImage) @@ -31,30 +36,36 @@ fun NewsItem(news: News, onClick: () -> Unit) { .build(), contentScale = ContentScale.FillWidth ) - Column(modifier = Modifier.fillMaxWidth().clickable { - onClick() - }) { - Image( - painter = painter, - contentDescription = null, - modifier = Modifier - .fillMaxWidth() - .height(200.dp), - ) - Text( - text = news.title, - style = MaterialTheme.typography.bodyMedium, - maxLines = 1, - modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) - ) - Text( - text = news.description, - style = MaterialTheme.typography.bodySmall, - maxLines = 3, - overflow = TextOverflow.Ellipsis, - color = Color.Gray, - modifier = Modifier.padding(horizontal = 8.dp) - ) + Card(modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp) + .clickable { + onClick() + }) { + Column() { + Image( + painter = painter, + contentDescription = null, + modifier = Modifier + .fillMaxWidth() + .height(200.dp), + contentScale = ContentScale.Crop + ) + Text( + text = news.title, + style = MaterialTheme.typography.bodyMedium, + maxLines = 1, + modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp) + ) + Text( + text = news.description, + style = MaterialTheme.typography.bodySmall, + maxLines = 3, + overflow = TextOverflow.Ellipsis, + color = Color.Gray, + modifier = Modifier.padding(start = 8.dp, end = 8.dp, bottom = 8.dp) + ) + } } } diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/Category.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/Category.kt new file mode 100644 index 0000000..9abad44 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/Category.kt @@ -0,0 +1,10 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.components.model + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class Category( + val pos: Int, + val name: String, +) : Parcelable \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/CategoryType.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/CategoryType.kt new file mode 100644 index 0000000..637eac4 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/components/model/CategoryType.kt @@ -0,0 +1,7 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.components.model + +enum class CategoryType { + GENERAL, + ENTERTAINMENT, + SPORTS +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt deleted file mode 100644 index dab26bb..0000000 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/detailscreen/Detailscreen.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui.detailscreen - -import androidx.compose.foundation.clickable -import androidx.compose.material3.Text -import androidx.compose.runtime.Composable -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import com.lahsuak.apps.jetpackcomposebasic.ui.openTab - -@Composable -fun DetailScreen(text: String) { - val context = LocalContext.current - Text(text = text, Modifier.clickable { - openTab(context, text) - }) -} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt deleted file mode 100644 index 403e280..0000000 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/home/HomeScreen.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui.home - -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items -import androidx.compose.runtime.Composable -import androidx.compose.runtime.collectAsState -import androidx.compose.runtime.getValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.unit.dp -import androidx.navigation.NavController -import com.lahsuak.apps.jetpackcomposebasic.model.News -import com.lahsuak.apps.jetpackcomposebasic.ui.NewsItem -import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel - -@Composable -fun HomeScreen( - navController: NavController, - newsViewModel: NewsViewModel -) { - - val newsList by newsViewModel.newsFlow.collectAsState() - LazyColumn(modifier = Modifier.padding(vertical = 4.dp)) { - items(items = newsList) { news -> - NewsItem( - news = news, - ) { - navController.currentBackStackEntry?.savedStateHandle?.set("news", news) - navController.navigate("details") - } - } - } -} - -@Composable -fun getList(): List { - val list = mutableListOf() - for (i in 0..10) { - list.add( - News( - "Kaushal", - "Ness", - "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", - "https://pixabay.com/get/gc5bde75f8a92a997aa842681d52d37e41990f5e639497bad55c1cf9921835528340e1269788a027624b201d17734fb431c5269478e54aece4e65f7581452fe98_640.jpg", - ) - ) - } - return list -} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavHost.kt similarity index 60% rename from app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt rename to app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavHost.kt index 4316a48..cf7d4e2 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/NavHost.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavHost.kt @@ -1,17 +1,16 @@ -package com.lahsuak.apps.jetpackcomposebasic.ui +package com.lahsuak.apps.jetpackcomposebasic.ui.navigation import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.lifecycle.viewmodel.compose.viewModel import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import com.lahsuak.apps.jetpackcomposebasic.model.News -import com.lahsuak.apps.jetpackcomposebasic.ui.detailscreen.DetailScreen -import com.lahsuak.apps.jetpackcomposebasic.ui.home.HomeScreen -import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel +import com.lahsuak.apps.jetpackcomposebasic.ui.screen.detailscreen.DetailScreen +import com.lahsuak.apps.jetpackcomposebasic.ui.screen.home.HomeScreen +private const val NEWS_ARG = "news" @Composable fun MyAppNavHost( modifier: Modifier = Modifier, @@ -24,16 +23,17 @@ fun MyAppNavHost( startDestination = startDestination ) { composable(NavigationItem.Home.route) { - val newsViewModel: NewsViewModel = viewModel() - newsViewModel.getNews("general") - HomeScreen( - navController, newsViewModel - ) + HomeScreen { + navController.currentBackStackEntry?.savedStateHandle?.set(NEWS_ARG, it) + navController.navigate(State.DETAILS.name) + } } composable(NavigationItem.Details.route) { val news = - navController.previousBackStackEntry?.savedStateHandle?.get("news") - DetailScreen(text = news?.url?:"") + navController.previousBackStackEntry?.savedStateHandle?.get(NEWS_ARG) + news?.let { + DetailScreen(it,navController) + } } } } \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavigationItem.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavigationItem.kt new file mode 100644 index 0000000..f1862c6 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/navigation/NavigationItem.kt @@ -0,0 +1,10 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.navigation + +enum class State{ + HOME, + DETAILS +} +sealed class NavigationItem(val route: String) { + object Home : NavigationItem(State.HOME.name) + object Details : NavigationItem(State.DETAILS.name) +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/detailscreen/Detailscreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/detailscreen/Detailscreen.kt new file mode 100644 index 0000000..51bf285 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/detailscreen/Detailscreen.kt @@ -0,0 +1,94 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.screen.detailscreen + +import androidx.compose.foundation.Image +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBar +import androidx.compose.material3.TopAppBarDefaults +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.navigation.NavHostController +import coil.compose.rememberAsyncImagePainter +import coil.request.ImageRequest +import com.lahsuak.apps.jetpackcomposebasic.R +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.util.AppUtil.openTab + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun DetailScreen(news: News, navController: NavHostController) { + val context = LocalContext.current + val scrollState = rememberScrollState() + + Box( + modifier = Modifier + .fillMaxSize() + .verticalScroll(scrollState) + ) { + Column { + TopAppBar(scrollBehavior = + TopAppBarDefaults.pinnedScrollBehavior(), + title = { + Text(text = "Details screen") + }, + navigationIcon = { + Icon( + imageVector = Icons.Default.ArrowBack, + contentDescription = "back", + modifier = Modifier.clickable { + navController.popBackStack() + } + ) + }) + + val painter = rememberAsyncImagePainter( + model = ImageRequest.Builder(LocalContext.current) + .data(news.urlToImage) + .placeholder(R.drawable.ic_launcher_foreground) + .crossfade(true) + .build(), + contentScale = ContentScale.FillBounds + ) + Image( + painter = painter, + contentDescription = news.title, + modifier = Modifier + .fillMaxWidth(), + contentScale = ContentScale.Crop + ) + Text(text = news.title, modifier = Modifier.padding(8.dp), fontSize = 20.sp) + Text( + text = news.description, + fontSize = 16.sp, + modifier = Modifier.padding(8.dp) + ) + Text( + text = context.getString(R.string.open_for_more), + style = TextStyle(color = Color.Blue), + modifier = Modifier + .padding(horizontal = 8.dp) + .clickable { + openTab(context, news.url) + } + ) + } + } +} + diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/home/HomeScreen.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/home/HomeScreen.kt new file mode 100644 index 0000000..37ac527 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/screen/home/HomeScreen.kt @@ -0,0 +1,60 @@ +package com.lahsuak.apps.jetpackcomposebasic.ui.screen.home + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.runtime.Composable +import androidx.compose.runtime.collectAsState +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.saveable.rememberSaveable +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp +import androidx.lifecycle.viewmodel.compose.viewModel +import com.lahsuak.apps.jetpackcomposebasic.model.News +import com.lahsuak.apps.jetpackcomposebasic.ui.components.ChipGroup +import com.lahsuak.apps.jetpackcomposebasic.ui.components.NewsItem +import com.lahsuak.apps.jetpackcomposebasic.ui.components.model.Category +import com.lahsuak.apps.jetpackcomposebasic.ui.components.model.CategoryType +import com.lahsuak.apps.jetpackcomposebasic.ui.viewmodel.NewsViewModel + +@Composable +fun HomeScreen(navController: (News) -> Unit) { + val newsViewModel: NewsViewModel = viewModel() + val newsList by newsViewModel.newsFlow.collectAsState() + val categories = listOf( + Category(0, CategoryType.GENERAL.name.lowercase()), + Category(1, CategoryType.ENTERTAINMENT.name.lowercase()), + Category(2, CategoryType.SPORTS.name.lowercase()) + ) + var selectedItem by rememberSaveable { + mutableStateOf(categories[0]) // initially, first item is selected + } + Box( + Modifier + .fillMaxSize() + ) { + Column { + ChipGroup( + categories, + selectedItem + ) { + selectedItem = it + newsViewModel.getNews(it.name) + } + LazyColumn(modifier = Modifier.padding(horizontal = 8.dp)) { + items(items = newsList) { news -> + NewsItem( + news = news, + ) { + navController(news) + } + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt index ad78a0c..cb1f208 100644 --- a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/ui/viewmodel/NewsViewModel.kt @@ -4,6 +4,8 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.lahsuak.apps.jetpackcomposebasic.model.News import com.lahsuak.apps.jetpackcomposebasic.repo.NewsRepository +import com.lahsuak.apps.jetpackcomposebasic.ui.components.model.Category +import com.lahsuak.apps.jetpackcomposebasic.ui.components.model.CategoryType import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.launch @@ -17,6 +19,9 @@ class NewsViewModel : ViewModel() { NewsRepository() } + init { + getNews(CategoryType.GENERAL.name.lowercase()) + } fun getNews(category: String) { viewModelScope.launch { val newsParentModel = newsRepo.getNews(category) diff --git a/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/util/AppUtil.kt b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/util/AppUtil.kt new file mode 100644 index 0000000..7688c33 --- /dev/null +++ b/app/src/main/java/com/lahsuak/apps/jetpackcomposebasic/util/AppUtil.kt @@ -0,0 +1,29 @@ +package com.lahsuak.apps.jetpackcomposebasic.util + +import android.content.Context +import android.net.Uri +import androidx.browser.customtabs.CustomTabsIntent +import java.io.InputStreamReader + +object AppUtil { + fun readFileResource(fileName: String): String { + val inputStream = AppUtil::class.java.getResourceAsStream(fileName) + val builder = StringBuilder() + val reader = InputStreamReader(inputStream, Charsets.UTF_8) + reader.readLines().forEach { + builder.append(it) + } + return builder.toString() + } + + fun openTab(context: Context, url: String) { + val packageName = "com.android.chrome" + val builder = CustomTabsIntent.Builder() + builder.setShowTitle(true) + builder.setInstantAppsEnabled(true) + val customBuilder = builder.build() + customBuilder.intent.setPackage(packageName) + customBuilder.launchUrl(context, Uri.parse(url)) + } +} + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17b9141..e373964 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ JetPackCompose Basic + Click here to see news in detail + Filter \ No newline at end of file diff --git a/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt b/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt index 68091df..3f08df2 100644 --- a/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt +++ b/app/src/test/java/com/lahsuak/apps/jetpackcomposebasic/NewsApiTest.kt @@ -1,7 +1,7 @@ package com.lahsuak.apps.jetpackcomposebasic import com.lahsuak.apps.jetpackcomposebasic.api.NewApi -import com.lahsuak.apps.jetpackcomposebasic.ui.Helper +import com.lahsuak.apps.jetpackcomposebasic.util.AppUtil import kotlinx.coroutines.runBlocking import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.MockWebServer @@ -32,7 +32,7 @@ class NewsApiTest { mockResponse.setBody("{}") mockWebServer.enqueue(mockResponse) - val response = newApi.getNews() + val response = newApi.getNews("general") mockWebServer.takeRequest() Assert.assertEquals(null, response.articles) } @@ -40,12 +40,12 @@ class NewsApiTest { @Test fun testGetNews_returnNews() = runBlocking { val mockResponse = MockResponse() - val content = Helper.readFileResource("/test.json") + val content = AppUtil.readFileResource("/test.json") mockResponse.setResponseCode(200) mockResponse.setBody(content) mockWebServer.enqueue(mockResponse) - val response = newApi.getNews() + val response = newApi.getNews("general") mockWebServer.takeRequest() Assert.assertEquals(true, response.articles.isNotEmpty()) Assert.assertEquals(2, response.articles.size) diff --git a/build.gradle b/build.gradle index e868fc8..13d8630 100644 --- a/build.gradle +++ b/build.gradle @@ -1,10 +1,10 @@ buildscript { ext { - compose_version = '1.3.2' + compose_version = '1.4.3' } }// Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id 'com.android.application' version '7.3.0' apply false - id 'com.android.library' version '7.3.0' apply false - id 'org.jetbrains.kotlin.android' version '1.6.10' apply false + id 'com.android.application' version '8.0.2' apply false + id 'com.android.library' version '8.0.2' apply false + id 'org.jetbrains.kotlin.android' version '1.8.0' apply false } \ No newline at end of file From db04a712c82bdc5572cef0589347e87f32046912 Mon Sep 17 00:00:00 2001 From: Kaushal Vasava <49050597+KaushalVasava@users.noreply.github.com> Date: Thu, 20 Jul 2023 18:31:46 +0530 Subject: [PATCH 4/4] Create README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..94dcca2 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# JetPackCompose_Basic +It is a basic functionality of jetpack compose UI element and how does it works.