diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..61a9130
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index 6cba290..3f80b50 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -18,5 +18,6 @@
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..d313a83
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 7bfef59..d5d35ec 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,6 +1,6 @@
-
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 232f105..9ad1a54 100644
--- a/README.md
+++ b/README.md
@@ -10,13 +10,13 @@ News App built with JetPack Compose
## The app contains following libraries
-- [Jetpack Compose(v0.1.0-dev14)] (https://developer.android.com/jetpack/compose) (UI)
+- [Jetpack Compose](https://developer.android.com/jetpack/compose) (UI)
-- [Koin](https://insert-koin.io/) (Dependency Injection)
+- [Dagger-Hilt](https://dagger.dev/hilt/) (Dependency Injection)
- [LifeCycle Components](https://developer.android.com/topic/libraries/architecture/livedata) (ViewModel and LiveData)
-- [Kotlin Corountines](https://kotlinlang.org/docs/reference/coroutines-overview.html) (Asynchronous programming)
+- [Kotlin Coroutines](https://kotlinlang.org/docs/reference/coroutines-overview.html) (Asynchronous programming)
- [Retrofit](https://square.github.io/retrofit/) (Networking)
diff --git a/app/build.gradle b/app/build.gradle
index f339cab..2967507 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,17 +2,18 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
+apply plugin: 'dagger.hilt.android.plugin'
android {
compileSdkVersion 29
defaultConfig {
- applicationId "com.akash.newzz_compose"
+ applicationId "com.akash.newzzcompose"
minSdkVersion 21
targetSdkVersion 29
- versionCode 2
- versionName "0.0.2"
+ versionCode 3
+ versionName "0.0.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -28,14 +29,15 @@ android {
}
kotlinOptions {
jvmTarget = '1.8'
+ useIR = true
}
buildFeatures {
compose true
}
composeOptions {
- kotlinCompilerVersion "1.3.70-dev-withExperimentalGoogleExtensions-20200424"
- kotlinCompilerExtensionVersion "0.1.0-dev14"
+ kotlinCompilerVersion "$kotlin_version"
+ kotlinCompilerExtensionVersion "$compose_version"
}
}
@@ -43,36 +45,45 @@ dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation project(':data')
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
- implementation 'androidx.core:core-ktx:1.3.0'
- implementation 'androidx.appcompat:appcompat:1.1.0'
+ implementation 'androidx.core:core-ktx:1.3.1'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation "androidx.activity:activity-ktx:1.1.0"
+ implementation 'android.arch.lifecycle:extensions:1.1.1'
/* ---------------------JetPack Compose-----------------------------*/
- implementation("androidx.compose:compose-runtime:$compose_version")
- implementation("androidx.ui:ui-core:$compose_version")
- implementation "androidx.ui:ui-layout:$compose_version"
- implementation "androidx.ui:ui-material:$compose_version"
- implementation "androidx.ui:ui-tooling:$compose_version"
- implementation "androidx.ui:ui-livedata:$compose_version"
+ implementation("androidx.compose.runtime:runtime:$compose_version")
+ implementation("androidx.compose.runtime:runtime-livedata:$compose_version")
+ implementation("androidx.compose.foundation:foundation:$compose_version")
+ implementation("androidx.compose.foundation:foundation-layout:$compose_version")
+
+ implementation("androidx.compose.ui:ui:$compose_version")
+ implementation("androidx.compose.material:material:$compose_version")
+ implementation("androidx.compose.material:material-icons-extended:$compose_version")
+
+ implementation("androidx.ui:ui-tooling:$compose_version")
/* ---------------------LifeCycle Extension-----------------------------*/
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
- /*-----------------------Koin-------------------------------------*/
- implementation "org.koin:koin-android:$koin_version"
- implementation "org.koin:koin-android-viewmodel:$koin_version"
+ /*------------------------Dagger Hilt----------------------------------*/
+ implementation "com.google.dagger:hilt-android:$hilt_version"
+ kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
+
+ implementation "androidx.hilt:hilt-lifecycle-viewmodel:$hilt_jetpack_config_version"
+ kapt "androidx.hilt:hilt-compiler:$hilt_jetpack_config_version"
/*---------------------ChromeCustomTab------------------------------*/
- implementation 'androidx.browser:browser:1.3.0-alpha04'
+ implementation 'androidx.browser:browser:1.3.0-alpha05'
/*---------------------CoilImageLoader------------------------------*/
- implementation "dev.chrisbanes.accompanist:accompanist-coil:0.1.6"
+ implementation "dev.chrisbanes.accompanist:accompanist-coil:0.2.0"
/*----------------------------Moshi-------------------------------------*/
implementation 'com.squareup.moshi:moshi:1.9.1'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
\ No newline at end of file
diff --git a/app/src/main/java/com/akash/newzz_compose/Category.kt b/app/src/main/java/com/akash/newzz_compose/Category.kt
deleted file mode 100644
index e5494eb..0000000
--- a/app/src/main/java/com/akash/newzz_compose/Category.kt
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.akash.newzz_compose
-
-import androidx.annotation.StringDef
-
-/**
- * Created by Akash on 06/06/20
- */
-
-@Retention(AnnotationRetention.SOURCE)
-@StringDef(value = [Category.GENERAL, Category.BUSINESS, Category.TECH])
-internal annotation class Category {
- companion object {
- const val GENERAL = "general"
- const val BUSINESS = "business"
- const val TECH = "technology"
- }
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt b/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt
index c3a967d..d41e8de 100644
--- a/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt
+++ b/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt
@@ -1,22 +1,14 @@
package com.akash.newzz_compose
import com.akash.newzz.data.BaseApplication
-import com.akash.newzz_compose.di.appModule
-import org.koin.android.ext.koin.androidContext
-import org.koin.android.ext.koin.androidLogger
-import org.koin.core.context.startKoin
+import dagger.hilt.android.HiltAndroidApp
/**
- * Created by Akash on 06/06/20
+ * Created by Akash on 28/08/20
*/
+@HiltAndroidApp
class NewzzApplication : BaseApplication() {
-
override fun onCreate() {
super.onCreate()
- startKoin {
- androidLogger()
- androidContext(this@NewzzApplication)
- modules(appModule)
- }
}
}
diff --git a/app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt b/app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt
new file mode 100644
index 0000000..9eb4249
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt
@@ -0,0 +1,35 @@
+package com.akash.newzz_compose.di
+
+import com.akash.newzz.data.apiservice.NewzzApiService
+import com.akash.newzz.data.repository.NewsRepository
+import com.akash.newzz.data.repository.NewsRepositoryImpl
+import com.squareup.moshi.Moshi
+import dagger.Module
+import dagger.Provides
+import dagger.hilt.InstallIn
+import dagger.hilt.android.components.ActivityComponent
+import dagger.hilt.android.scopes.ActivityScoped
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+@Module
+@InstallIn(ActivityComponent::class)
+object NewzzActivityModule {
+
+ @Provides
+ @ActivityScoped
+ fun provideNewsApiService(): NewzzApiService = NewzzApiService()
+
+ @Provides
+ @ActivityScoped
+ fun provideNewsRepo(
+ apiService: NewzzApiService,
+ moshi: Moshi
+ ): NewsRepository = NewsRepositoryImpl(apiService, moshi)
+
+ @Provides
+ @ActivityScoped
+ fun provideMoshi(): Moshi = Moshi.Builder().build()
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/di/module.kt b/app/src/main/java/com/akash/newzz_compose/di/module.kt
deleted file mode 100644
index f7e8e28..0000000
--- a/app/src/main/java/com/akash/newzz_compose/di/module.kt
+++ /dev/null
@@ -1,20 +0,0 @@
-package com.akash.newzz_compose.di
-
-import com.akash.newzz.data.apiservice.NewzzApiService
-import com.akash.newzz.data.repository.NewsRepository
-import com.akash.newzz.data.repository.NewsRepositoryImpl
-import com.akash.newzz_compose.viewmodel.NewzzViewModel
-import com.squareup.moshi.Moshi
-import org.koin.android.viewmodel.dsl.viewModel
-import org.koin.dsl.module
-
-/**
- * Created by Akash on 06/06/20
- */
-
-val appModule = module {
- viewModel { NewzzViewModel(get()) }
- single { NewsRepositoryImpl(get(), get()) as NewsRepository }
- single { NewzzApiService() }
- single { Moshi.Builder().build() }
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/other/Category.kt b/app/src/main/java/com/akash/newzz_compose/other/Category.kt
new file mode 100644
index 0000000..1082eba
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/other/Category.kt
@@ -0,0 +1,34 @@
+package com.akash.newzz_compose.other
+
+import com.akash.newzz_compose.R
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+interface Category {
+ val category: String
+ val icon: Int
+}
+
+data class General(
+ override val category: String = "general",
+ override val icon: Int = R.drawable.ic_general
+) : Category
+
+data class Business(
+ override val category: String = "business",
+ override val icon: Int = R.drawable.ic_business
+) : Category
+
+data class Technology(
+ override val category: String = "technology",
+ override val icon: Int = R.drawable.ic_tech
+) : Category
+
+fun getTitleResource(activeCategory: Category): Int = when (activeCategory) {
+ is General -> R.string.title_general
+ is Business -> R.string.title_business
+ is Technology -> R.string.title_technology
+ else -> throw IllegalAccessException("Page number is invalid")
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/style/Color.kt b/app/src/main/java/com/akash/newzz_compose/style/Color.kt
deleted file mode 100644
index 06344f7..0000000
--- a/app/src/main/java/com/akash/newzz_compose/style/Color.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.akash.newzz_compose.style
-
-import androidx.ui.graphics.Color
-
-/**
- * Created by Akash on 07/06/20
- */
-
-val deepPurple = Color(0xFF4a148c)
-val darkColor = Color(0xFF121212)
-
-val sourceTextColor = Color(0xFF474646)
-val sourceTextColorDark = Color(0xFF868080)
-
-val titleColor = Color.Black
-val titleColorDark = Color(0xB3DCDCDC)
-
-val listBackgroundColor = Color.White
-val listBackgroundColorDark = Color(0xFF1E1E1E)
-
-val bottomNavBackground = Color.White
-val bottomNavBackgroundDark = Color(0xFF222222)
-
-val bottomNavIconActiveColor = Color(0xFF4a148c)
-val bottomNavIconInActiveColor = Color.Black
-
-val bottomNavIconActiveColorDark = Color(0xB3DCDCDC)
-val bottomNavIconInActiveColorDark = Color(0xFF5C5757)
-
-val circularLoaderColor = deepPurple
-val circularLoaderColorDark = Color.White
-
-val dividerColor = Color(0xFFDCDCDC)
-val dividerColorDark = Color(0xFF2B2929)
diff --git a/app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt b/app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt
deleted file mode 100644
index 1e1ac79..0000000
--- a/app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.akash.newzz_compose.style
-
-import androidx.ui.graphics.Color
-import androidx.ui.text.TextStyle
-import androidx.ui.text.font.FontWeight
-import androidx.ui.unit.sp
-
-/**
- * Created by Akash on 07/06/20
- */
-
-val categoryTitleStyle = TextStyle(
- fontWeight = FontWeight.Bold,
- fontSize = 20.sp,
- color = Color.White
-)
-
-val articleTitleStyle = TextStyle(
- fontWeight = FontWeight.Medium,
- fontSize = 16.sp,
- color = titleColor
-)
-
-val sourceTextStyle = TextStyle(
- fontSize = 14.sp,
- color = sourceTextColor
-)
-
-val dateTextStyle = TextStyle(
- fontWeight = FontWeight.ExtraLight,
- fontSize = 12.sp,
- color = sourceTextColor
-)
diff --git a/app/src/main/java/com/akash/newzz_compose/style/Theme.kt b/app/src/main/java/com/akash/newzz_compose/style/Theme.kt
deleted file mode 100644
index 1e03e83..0000000
--- a/app/src/main/java/com/akash/newzz_compose/style/Theme.kt
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.akash.newzz_compose.style
-
-import androidx.ui.material.darkColorPalette
-import androidx.ui.material.lightColorPalette
-
-/**
- * Created by Akash on 05/06/20
- */
-
-val themeColor = lightColorPalette(
- primary = deepPurple,
- primaryVariant = deepPurple,
- secondary = deepPurple,
- secondaryVariant = deepPurple,
- surface = deepPurple,
- background = deepPurple
-)
-
-val darkThemeColor = darkColorPalette(
- primary = darkColor,
- primaryVariant = darkColor,
- secondary = darkColor,
- surface = darkColor
-)
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/NewzzActivity.kt b/app/src/main/java/com/akash/newzz_compose/ui/NewzzActivity.kt
index 19e1c8d..072f087 100644
--- a/app/src/main/java/com/akash/newzz_compose/ui/NewzzActivity.kt
+++ b/app/src/main/java/com/akash/newzz_compose/ui/NewzzActivity.kt
@@ -1,25 +1,31 @@
package com.akash.newzz_compose.ui
import android.os.Bundle
+import android.util.Log
+import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
-import androidx.ui.core.setContent
-import androidx.ui.livedata.observeAsState
-import androidx.ui.material.MaterialTheme
-import com.akash.newzz_compose.style.darkThemeColor
-import com.akash.newzz_compose.style.themeColor
-import com.akash.newzz_compose.ui.home.Home
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.platform.setContent
+import com.akash.newzz_compose.ui.newzzappui.NewzzAppUI
+import com.akash.newzz_compose.ui.style.NewzzTheme
import com.akash.newzz_compose.viewmodel.NewzzViewModel
-import org.koin.android.viewmodel.ext.android.viewModel
+import dagger.hilt.android.AndroidEntryPoint
+/**
+ * Created by Akash on 27/08/20
+ */
+@AndroidEntryPoint
class NewzzActivity : AppCompatActivity() {
- private val viewModel: NewzzViewModel by viewModel()
+
+ private val viewModel: NewzzViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
- val isDark = viewModel.isDarkTheme.observeAsState(false)
- MaterialTheme(colors = if (isDark.value) darkThemeColor else themeColor) {
- Home(viewModel)
+ val darkTheme = viewModel.isDarkTheme.observeAsState(false)
+ Log.d("THEME", "darkTheme: ${darkTheme.value}")
+ NewzzTheme(darkTheme = darkTheme.value) {
+ NewzzAppUI(viewModel = viewModel)
}
}
}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/articlelist/ArticleListScreen.kt b/app/src/main/java/com/akash/newzz_compose/ui/articlelist/ArticleListScreen.kt
deleted file mode 100644
index 186ad91..0000000
--- a/app/src/main/java/com/akash/newzz_compose/ui/articlelist/ArticleListScreen.kt
+++ /dev/null
@@ -1,93 +0,0 @@
-package com.akash.newzz_compose.ui.articlelist
-
-import androidx.compose.Composable
-import androidx.compose.State
-import androidx.ui.core.Alignment
-import androidx.ui.core.ContextAmbient
-import androidx.ui.core.Modifier
-import androidx.ui.foundation.Box
-import androidx.ui.foundation.Text
-import androidx.ui.foundation.clickable
-import androidx.ui.foundation.lazy.LazyColumnItems
-import androidx.ui.layout.Column
-import androidx.ui.layout.Row
-import androidx.ui.layout.padding
-import androidx.ui.layout.preferredHeight
-import androidx.ui.layout.preferredWidth
-import androidx.ui.material.Divider
-import androidx.ui.text.style.TextOverflow
-import androidx.ui.unit.dp
-import com.akash.newzz.data.response.NewsArticle
-import com.akash.newzz_compose.style.articleTitleStyle
-import com.akash.newzz_compose.style.dateTextStyle
-import com.akash.newzz_compose.style.dividerColor
-import com.akash.newzz_compose.style.dividerColorDark
-import com.akash.newzz_compose.style.sourceTextColorDark
-import com.akash.newzz_compose.style.sourceTextStyle
-import com.akash.newzz_compose.style.titleColorDark
-import com.akash.newzz_compose.ui.common.HeightSpacer
-import com.akash.newzz_compose.ui.common.RemoteImage
-import com.akash.newzz_compose.ui.common.WidthSpacer
-import com.akash.newzz_compose.utils.CustomTabUtil
-
-/**
- * Created by Akash on 06/06/20
- */
-
-@Composable
-fun ArticleRow(article: NewsArticle, isDark: State, onClick: () -> Unit) {
- Box(modifier = Modifier.clickable(onClick = { onClick() })) {
- Row(
- modifier = Modifier.padding(all = 10.dp),
- verticalGravity = Alignment.CenterVertically
- ) {
- RemoteImage(
- url = article.urlToImage,
- modifier = Modifier.preferredHeight(100.dp)
- .plus(Modifier.preferredWidth(100.dp))
- )
- WidthSpacer(value = 10.dp)
- Column {
- if (!article.source.name.isNullOrEmpty()) {
- Text(
- text = article.source.name!!,
- style = if (isDark.value) sourceTextStyle.copy(color = sourceTextColorDark) else sourceTextStyle
- )
- HeightSpacer(value = 4.dp)
- }
- Text(
- text = article.title,
- style = if (isDark.value) articleTitleStyle.copy(color = titleColorDark) else articleTitleStyle,
- maxLines = 3,
- overflow = TextOverflow.Ellipsis
- )
- HeightSpacer(value = 4.dp)
- Text(
- text = article.publishedAt.substring(0, 10),
- style = if (isDark.value) dateTextStyle.copy(color = sourceTextColorDark) else dateTextStyle
- )
- }
- }
- }
-}
-
-@Composable
-fun ArticleList(articles: List, isDark: State) {
- val context = ContextAmbient.current
- LazyColumnItems(
- items = articles,
- itemContent = { article: NewsArticle ->
- ArticleRow(
- article = article,
- isDark = isDark,
- onClick = {
- CustomTabUtil.launch(context, article.url.toString(), isDark.value)
- }
- )
- HeightSpacer(value = 10.dp)
- Divider(
- color = if (isDark.value) dividerColorDark else dividerColor
- )
- }
- )
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/common/Common.kt b/app/src/main/java/com/akash/newzz_compose/ui/common/Common.kt
deleted file mode 100644
index dcfec08..0000000
--- a/app/src/main/java/com/akash/newzz_compose/ui/common/Common.kt
+++ /dev/null
@@ -1,73 +0,0 @@
-package com.akash.newzz_compose.ui.common
-
-import androidx.compose.Composable
-import androidx.ui.core.Alignment
-import androidx.ui.core.ContentScale
-import androidx.ui.core.Modifier
-import androidx.ui.foundation.Box
-import androidx.ui.foundation.Image
-import androidx.ui.foundation.shape.corner.RoundedCornerShape
-import androidx.ui.graphics.Color
-import androidx.ui.graphics.Shape
-import androidx.ui.graphics.vector.VectorAsset
-import androidx.ui.layout.Spacer
-import androidx.ui.layout.Stack
-import androidx.ui.layout.fillMaxSize
-import androidx.ui.layout.preferredHeight
-import androidx.ui.layout.preferredWidth
-import androidx.ui.material.CircularProgressIndicator
-import androidx.ui.material.Surface
-import androidx.ui.res.vectorResource
-import androidx.ui.unit.Dp
-import androidx.ui.unit.dp
-import com.akash.newzz_compose.R
-import dev.chrisbanes.accompanist.coil.CoilImageWithCrossfade
-
-/**
- * Created by Akash on 07/06/20
- */
-
-@Composable
-fun HeightSpacer(value: Dp) {
- Spacer(modifier = Modifier.preferredHeight(value))
-}
-
-@Composable
-fun WidthSpacer(value: Dp) {
- Spacer(modifier = Modifier.preferredWidth(value))
-}
-
-@Composable
-fun RemoteImage(
- url: String?,
- modifier: Modifier,
- errorImage: VectorAsset = vectorResource(id = R.drawable.ic_newzz_error),
- contentScale: ContentScale = ContentScale.Crop,
- shape: Shape = RoundedCornerShape(5.dp)
-) {
- Box(
- modifier = modifier
- ) {
- if (url.isNullOrEmpty()) {
- Image(
- modifier = Modifier.fillMaxSize(),
- asset = errorImage
- )
- } else {
- Surface(
- color = Color.Transparent,
- shape = shape
- ) {
- CoilImageWithCrossfade(
- data = url,
- contentScale = contentScale,
- loading = {
- Stack(Modifier.fillMaxSize()) {
- CircularProgressIndicator(Modifier.gravity(Alignment.Center))
- }
- }
- )
- }
- }
- }
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/commoncomposable/CommonComposables.kt b/app/src/main/java/com/akash/newzz_compose/ui/commoncomposable/CommonComposables.kt
new file mode 100644
index 0000000..6c09b6a
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/commoncomposable/CommonComposables.kt
@@ -0,0 +1,81 @@
+package com.akash.newzz_compose.ui.commoncomposable
+
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.layout.*
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.CircularProgressIndicator
+import androidx.compose.material.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.BlendMode
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.Shape
+import androidx.compose.ui.graphics.vector.VectorAsset
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import com.akash.newzz_compose.R
+import com.akash.newzz_compose.ui.style.NewzzTheme
+import com.akash.newzz_compose.ui.style.titleColorDark
+import dev.chrisbanes.accompanist.coil.CoilImage
+
+/**
+ * Created by Akash on 29/08/20
+ */
+
+@Composable
+fun HeightSpacer(value: Dp) {
+ Spacer(modifier = Modifier.preferredHeight(value))
+}
+
+@Composable
+fun WidthSpacer(value: Dp) {
+ Spacer(modifier = Modifier.preferredWidth(value))
+}
+
+@Composable
+fun RemoteImage(
+ url: String?,
+ modifier: Modifier,
+ errorImage: VectorAsset = vectorResource(id = R.drawable.ic_newzz_error),
+ contentScale: ContentScale = ContentScale.Crop,
+ shape: Shape = RoundedCornerShape(5.dp)
+) {
+ Box(
+ modifier = modifier
+ ) {
+ if (url.isNullOrEmpty()) {
+ Image(
+ modifier = Modifier.fillMaxSize(),
+ asset = errorImage,
+ colorFilter = ColorFilter(
+ color = if (NewzzTheme.colors.isDark) titleColorDark else Color.Black,
+ blendMode = BlendMode.SrcAtop
+ )
+ )
+ } else {
+ Surface(
+ color = Color.Transparent,
+ shape = shape
+ ) {
+ CoilImage(
+ data = url,
+ modifier = modifier,
+ contentScale = contentScale,
+ loading = {
+ Stack(Modifier.fillMaxSize()) {
+ CircularProgressIndicator(
+ color = NewzzTheme.colors.circularLoaderColor,
+ modifier = Modifier.gravity(Alignment.Center)
+ )
+ }
+ }
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/home/BodyContent.kt b/app/src/main/java/com/akash/newzz_compose/ui/home/BodyContent.kt
deleted file mode 100644
index f37a136..0000000
--- a/app/src/main/java/com/akash/newzz_compose/ui/home/BodyContent.kt
+++ /dev/null
@@ -1,194 +0,0 @@
-package com.akash.newzz_compose.ui.home
-
-import androidx.compose.Composable
-import androidx.compose.State
-import androidx.ui.core.Alignment
-import androidx.ui.core.Modifier
-import androidx.ui.foundation.Box
-import androidx.ui.foundation.Icon
-import androidx.ui.foundation.Text
-import androidx.ui.foundation.shape.corner.RoundedCornerShape
-import androidx.ui.graphics.Color
-import androidx.ui.layout.Arrangement
-import androidx.ui.layout.Column
-import androidx.ui.layout.Row
-import androidx.ui.layout.fillMaxSize
-import androidx.ui.layout.fillMaxWidth
-import androidx.ui.layout.padding
-import androidx.ui.livedata.observeAsState
-import androidx.ui.material.CircularProgressIndicator
-import androidx.ui.material.IconButton
-import androidx.ui.material.Surface
-import androidx.ui.material.TextButton
-import androidx.ui.res.vectorResource
-import androidx.ui.text.TextStyle
-import androidx.ui.unit.dp
-import com.akash.newzz_compose.Category
-import com.akash.newzz_compose.R
-import com.akash.newzz_compose.style.articleTitleStyle
-import com.akash.newzz_compose.style.categoryTitleStyle
-import com.akash.newzz_compose.style.circularLoaderColor
-import com.akash.newzz_compose.style.circularLoaderColorDark
-import com.akash.newzz_compose.style.deepPurple
-import com.akash.newzz_compose.style.listBackgroundColor
-import com.akash.newzz_compose.style.listBackgroundColorDark
-import com.akash.newzz_compose.style.sourceTextColorDark
-import com.akash.newzz_compose.style.titleColorDark
-import com.akash.newzz_compose.ui.articlelist.ArticleList
-import com.akash.newzz_compose.viewmodel.NewzzViewModel
-
-/**
- * Created by Akash on 05/06/20
- */
-
-@Composable
-fun BodyContent(viewModel: NewzzViewModel) {
- val page = viewModel.pageNumber.observeAsState(NewzzViewModel.General)
- val generalState = viewModel.generalState.observeAsState(NewzzViewModel.ArticleState())
- val businessState = viewModel.businessState.observeAsState(NewzzViewModel.ArticleState())
- val techState = viewModel.techState.observeAsState(NewzzViewModel.ArticleState())
- val isDark = viewModel.isDarkTheme.observeAsState(false)
- Surface(modifier = Modifier.fillMaxSize()) {
- Column(modifier = Modifier.fillMaxWidth()) {
- TopAppBar(viewModel)
- Surface(
- color = if (isDark.value) listBackgroundColorDark else listBackgroundColor,
- shape = RoundedCornerShape(topLeft = 5.dp, topRight = 5.dp),
- modifier = Modifier.fillMaxSize().padding(
- start = 10.dp,
- end = 10.dp,
- bottom = 54.dp
- )
- ) {
- when (page.value) {
- NewzzViewModel.General -> ArticleStateWidget(
- state = generalState,
- isDark = isDark,
- onClick = {
- viewModel.performAction(NewzzViewModel.Action.FetchArticles(Category.GENERAL))
- }
- )
- NewzzViewModel.Business -> ArticleStateWidget(
- state = businessState,
- isDark = isDark,
- onClick = {
- viewModel.performAction(NewzzViewModel.Action.FetchArticles(Category.BUSINESS))
- }
- )
- NewzzViewModel.Technology -> ArticleStateWidget(
- state = techState,
- isDark = isDark,
- onClick = {
- viewModel.performAction(NewzzViewModel.Action.FetchArticles(Category.TECH))
- }
- )
- }
- }
- }
- }
-}
-
-@Composable
-fun TopAppBar(viewModel: NewzzViewModel) {
- val page = viewModel.pageNumber.observeAsState(NewzzViewModel.General)
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.SpaceBetween,
- verticalGravity = Alignment.CenterVertically
- ) {
- Text(
- modifier = Modifier.padding(top = 40.dp, start = 16.dp, end = 16.dp, bottom = 16.dp),
- text = getTitle(page.value),
- style = categoryTitleStyle
- )
- Box(modifier = Modifier.padding(top = 24.dp, end = 8.dp)) {
- ThemeSwitcher(viewModel = viewModel)
- }
- }
-}
-
-@Composable
-fun ArticleStateWidget(
- state: State,
- isDark: State,
- onClick: () -> Unit
-) {
- when {
- state.value.isLoading -> {
- Loading(isDark)
- }
- state.value.list != null -> {
- ArticleList(articles = state.value.list!!, isDark = isDark)
- }
- else -> {
- ErrorView(
- errorMessage = state.value.error!!.errorMessage,
- showRetry = state.value.error!!.showRetry,
- onClick = onClick,
- isDark = isDark
- )
- }
- }
-}
-
-@Composable
-fun ThemeSwitcher(viewModel: NewzzViewModel) {
- val isDark = viewModel.isDarkTheme.observeAsState(false)
- val light = vectorResource(id = R.drawable.ic_light)
- val dark = vectorResource(id = R.drawable.ic_dark)
- IconButton(onClick = {
- viewModel.performAction(NewzzViewModel.Action.SwitchTheme)
- }) {
- Icon(
- asset = if (isDark.value) light else dark,
- tint = Color.White
- )
- }
-}
-
-@Composable
-fun Loading(isDark: State) {
- Column(
- verticalArrangement = Arrangement.Center,
- horizontalGravity = Alignment.CenterHorizontally
- ) {
- CircularProgressIndicator(
- color = if (isDark.value) circularLoaderColorDark else circularLoaderColor
- )
- }
-}
-
-@Composable
-fun ErrorView(
- errorMessage: String,
- showRetry: Boolean,
- isDark: State,
- onClick: () -> Unit
-) {
- Column(
- verticalArrangement = Arrangement.Center,
- horizontalGravity = Alignment.CenterHorizontally
- ) {
- Text(
- text = errorMessage,
- style = if (isDark.value) articleTitleStyle.copy(color = titleColorDark) else articleTitleStyle
- )
- if (showRetry) {
- TextButton(onClick = onClick) {
- Text(
- text = "Retry",
- style = TextStyle(
- color = if (isDark.value) sourceTextColorDark else deepPurple
- )
- )
- }
- }
- }
-}
-
-private fun getTitle(pageNumber: Int): String = when (pageNumber) {
- 1 -> "General"
- 2 -> "Business"
- 3 -> "Technology"
- else -> throw IllegalAccessException("Page number is invalid")
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/home/BottomBar.kt b/app/src/main/java/com/akash/newzz_compose/ui/home/BottomBar.kt
deleted file mode 100644
index 686d3a0..0000000
--- a/app/src/main/java/com/akash/newzz_compose/ui/home/BottomBar.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.akash.newzz_compose.ui.home
-
-import androidx.compose.Composable
-import androidx.compose.State
-import androidx.ui.core.Modifier
-import androidx.ui.foundation.Icon
-import androidx.ui.layout.Arrangement
-import androidx.ui.layout.Row
-import androidx.ui.livedata.observeAsState
-import androidx.ui.material.BottomAppBar
-import androidx.ui.material.IconButton
-import androidx.ui.res.vectorResource
-import com.akash.newzz_compose.R
-import com.akash.newzz_compose.style.bottomNavBackground
-import com.akash.newzz_compose.style.bottomNavBackgroundDark
-import com.akash.newzz_compose.style.bottomNavIconActiveColor
-import com.akash.newzz_compose.style.bottomNavIconActiveColorDark
-import com.akash.newzz_compose.style.bottomNavIconInActiveColor
-import com.akash.newzz_compose.style.bottomNavIconInActiveColorDark
-import com.akash.newzz_compose.viewmodel.NewzzViewModel
-
-/**
- * Created by Akash on 05/06/20
- */
-
-@Composable
-fun BottomBar(viewModel: NewzzViewModel) {
- val isDark = viewModel.isDarkTheme.observeAsState(false)
- BottomAppBar(backgroundColor = if (isDark.value) bottomNavBackgroundDark else bottomNavBackground) {
- val page = viewModel.pageNumber.observeAsState(NewzzViewModel.General)
- Row(
- modifier = Modifier.weight(1f),
- horizontalArrangement = Arrangement.SpaceAround
- ) {
- BottomNavItem(
- asset = R.drawable.ic_general,
- isSelected = page.value == NewzzViewModel.General,
- isDark = isDark,
- onClick = {
- if (page.value != NewzzViewModel.General) {
- viewModel.performAction(
- NewzzViewModel.Action.ChangePageTo(
- NewzzViewModel.General
- )
- )
- }
- }
- )
- BottomNavItem(
- asset = R.drawable.ic_business,
- isSelected = page.value == NewzzViewModel.Business,
- isDark = isDark,
- onClick = {
- if (page.value != NewzzViewModel.Business) {
- viewModel.performAction(
- NewzzViewModel.Action.ChangePageTo(
- NewzzViewModel.Business
- )
- )
- }
- }
- )
- BottomNavItem(
- asset = R.drawable.ic_tech,
- isSelected = page.value == NewzzViewModel.Technology,
- isDark = isDark,
- onClick = {
- if (page.value != NewzzViewModel.Technology) {
- viewModel.performAction(
- NewzzViewModel.Action.ChangePageTo(
- NewzzViewModel.Technology
- )
- )
- }
- }
- )
- }
- }
-}
-
-@Composable
-fun BottomNavItem(
- asset: Int,
- isDark: State,
- onClick: () -> Unit,
- isSelected: Boolean = false
-) {
- IconButton(onClick = onClick) {
- Icon(
- asset = vectorResource(id = asset),
- tint = if (isDark.value) {
- if (isSelected) bottomNavIconActiveColorDark else bottomNavIconInActiveColorDark
- } else {
- if (isSelected) bottomNavIconActiveColor else bottomNavIconInActiveColor
- }
- )
- }
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/home/Home.kt b/app/src/main/java/com/akash/newzz_compose/ui/home/Home.kt
deleted file mode 100644
index 2ed7fd6..0000000
--- a/app/src/main/java/com/akash/newzz_compose/ui/home/Home.kt
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.akash.newzz_compose.ui.home
-
-import androidx.compose.Composable
-import androidx.ui.material.Scaffold
-import com.akash.newzz_compose.viewmodel.NewzzViewModel
-
-/**
- * Created by Akash on 05/06/20
- */
-
-@Composable
-fun Home(
- viewModel: NewzzViewModel
-) {
- Scaffold(
- bodyContent = { BodyContent(viewModel) },
- bottomBar = { BottomBar(viewModel) }
- )
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleList.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleList.kt
new file mode 100644
index 0000000..e2af57e
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleList.kt
@@ -0,0 +1,86 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.preferredSize
+import androidx.compose.foundation.lazy.LazyColumnFor
+import androidx.compose.material.Divider
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.platform.ContextAmbient
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import com.akash.newzz.data.response.NewsArticle
+import com.akash.newzz_compose.ui.commoncomposable.HeightSpacer
+import com.akash.newzz_compose.ui.commoncomposable.RemoteImage
+import com.akash.newzz_compose.ui.commoncomposable.WidthSpacer
+import com.akash.newzz_compose.ui.style.NewzzTheme
+import com.akash.newzz_compose.ui.style.articleTitleStyle
+import com.akash.newzz_compose.ui.style.dateTextStyle
+import com.akash.newzz_compose.ui.style.sourceTextStyle
+import com.akash.newzz_compose.util.CustomTabUtil
+
+/**
+ * Created by Akash on 29/08/20
+ */
+
+@Composable
+fun ArticleRow(article: NewsArticle, onClick: () -> Unit) {
+ Column(modifier = Modifier.clickable(onClick = { onClick() })) {
+ Row(
+ modifier = Modifier.padding(all = 10.dp),
+ verticalGravity = Alignment.CenterVertically
+ ) {
+ RemoteImage(
+ url = article.urlToImage,
+ modifier = Modifier.preferredSize(100.dp)
+ )
+ WidthSpacer(value = 10.dp)
+ Column {
+ if (!article.source.name.isNullOrEmpty()) {
+ Text(
+ text = article.source.name!!,
+ style = sourceTextStyle.copy(color = NewzzTheme.colors.sourceColor)
+ )
+ HeightSpacer(value = 4.dp)
+ }
+ Text(
+ text = article.title,
+ style = articleTitleStyle.copy(color = NewzzTheme.colors.titleColor),
+ maxLines = 3,
+ overflow = TextOverflow.Ellipsis
+ )
+ HeightSpacer(value = 4.dp)
+ Text(
+ text = article.publishedAt.substring(0, 10),
+ style = dateTextStyle.copy(color = NewzzTheme.colors.sourceColor)
+ )
+ }
+ }
+ HeightSpacer(value = 10.dp)
+ Divider(
+ color = NewzzTheme.colors.dividerColor
+ )
+ }
+}
+
+@Composable
+fun ArticleList(articles: List) {
+ val context = ContextAmbient.current
+ val isDark = NewzzTheme.colors.isDark
+ LazyColumnFor(
+ items = articles,
+ itemContent = { article: NewsArticle ->
+ ArticleRow(
+ article = article,
+ onClick = {
+ CustomTabUtil.launch(context, article.url.toString(), isDark)
+ }
+ )
+ }
+ )
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleListUiState.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleListUiState.kt
new file mode 100644
index 0000000..3a145ee
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleListUiState.kt
@@ -0,0 +1,14 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import com.akash.newzz.data.Result
+import com.akash.newzz.data.response.NewsArticle
+
+/**
+ * Created by Akash on 29/08/20
+ */
+
+data class ArticleListUiState(
+ val isLoading: Boolean = true,
+ val list: List? = emptyList(),
+ val error: Result.Error? = null
+)
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt
new file mode 100644
index 0000000..5fb41e8
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt
@@ -0,0 +1,48 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import androidx.compose.foundation.Icon
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.preferredHeight
+import androidx.compose.material.BottomAppBar
+import androidx.compose.material.BottomNavigationItem
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.unit.dp
+import com.akash.newzz_compose.other.Category
+import com.akash.newzz_compose.ui.style.NewzzTheme
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+@Composable
+fun BottomBar(
+ categoryList: List,
+ activeCategory: Category,
+ onMenuClicked: (Category) -> Unit
+) {
+ BottomAppBar(
+ backgroundColor = NewzzTheme.colors.bottomNavBackground,
+ elevation = 10.dp
+ ) {
+ Row(
+ modifier = Modifier.fillMaxWidth().preferredHeight(50.dp),
+ horizontalArrangement = Arrangement.SpaceAround
+ ) {
+ categoryList.forEach { category ->
+ BottomNavigationItem(
+ icon = { Icon(asset = vectorResource(id = category.icon)) },
+ selected = activeCategory == category,
+ onSelect = {
+ onMenuClicked(category)
+ },
+ selectedContentColor = NewzzTheme.colors.bottomNavActiveIconColor,
+ unselectedContentColor = NewzzTheme.colors.bottomNavInActiveIconColor
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt
new file mode 100644
index 0000000..9370667
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt
@@ -0,0 +1,73 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material.Scaffold
+import androidx.compose.material.Surface
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.livedata.observeAsState
+import androidx.compose.ui.Modifier
+import com.akash.newzz_compose.other.Category
+import com.akash.newzz_compose.other.getTitleResource
+import com.akash.newzz_compose.ui.style.NewzzTheme
+import com.akash.newzz_compose.viewmodel.NewzzViewModel
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+@Composable
+fun NewzzAppUI(viewModel: NewzzViewModel) {
+ val categoryList = viewModel.categoryList.observeAsState().value!!
+ val activeCategory = viewModel.activeCategory.observeAsState().value!!
+ val activeCategoryUiState = viewModel.activeCategoryUiState.observeAsState().value!!
+ Scaffold(
+ bodyContent = {
+ BodyContent(
+ activeCategory = activeCategory,
+ onThemeSwitch = {
+ viewModel.performAction(NewzzViewModel.Action.SwitchTheme)
+ },
+ activeCategoryUiState = activeCategoryUiState,
+ retryFetchingArticles = { category ->
+ viewModel.performAction(NewzzViewModel.Action.FetchArticles(category))
+ }
+ )
+ },
+ bottomBar = {
+ BottomBar(
+ categoryList = categoryList,
+ onMenuClicked = { category ->
+ viewModel.performAction(NewzzViewModel.Action.ChangePageTo(category))
+ },
+ activeCategory = activeCategory
+ )
+ }
+ )
+}
+
+@Composable
+fun BodyContent(
+ activeCategory: Category,
+ activeCategoryUiState: ArticleListUiState,
+ onThemeSwitch: () -> Unit,
+ retryFetchingArticles: (Category) -> Unit
+) {
+ val stringRes = getTitleResource(activeCategory)
+ Surface(
+ modifier = Modifier.fillMaxSize(),
+ color = NewzzTheme.colors.primaryColor
+ ) {
+ Column(modifier = Modifier.fillMaxSize()) {
+ TopAppBar(stringRes, onThemeSwitch = {
+ onThemeSwitch()
+ })
+ NewzzListContainer(
+ uiState = activeCategoryUiState,
+ retry = {
+ retryFetchingArticles(activeCategory)
+ }
+ )
+ }
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzListContainer.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzListContainer.kt
new file mode 100644
index 0000000..303451a
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzListContainer.kt
@@ -0,0 +1,98 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.CircularProgressIndicator
+import androidx.compose.material.Surface
+import androidx.compose.material.TextButton
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.unit.dp
+import com.akash.newzz_compose.R
+import com.akash.newzz_compose.ui.style.NewzzTheme
+import com.akash.newzz_compose.ui.style.articleTitleStyle
+
+/**
+ * Created by Akash on 29/08/20
+ */
+
+@Composable
+fun NewzzListContainer(
+ uiState: ArticleListUiState,
+ retry: () -> Unit
+) {
+ Surface(
+ color = NewzzTheme.colors.backGroundColor,
+ shape = RoundedCornerShape(topLeft = 5.dp, topRight = 5.dp),
+ modifier = Modifier.fillMaxSize().padding(
+ start = 10.dp,
+ end = 10.dp,
+ bottom = 50.dp
+ )
+ ) {
+ when {
+ uiState.isLoading -> {
+ CircularLoader()
+ }
+ uiState.error != null -> {
+ ErrorView(
+ errorMessage = uiState.error.errorMessage,
+ showRetry = uiState.error.showRetry,
+ retry = retry
+ )
+ }
+ uiState.list?.isEmpty() == false -> {
+ ArticleList(
+ articles = uiState.list
+ )
+ }
+ }
+ }
+}
+
+
+@Composable
+private fun CircularLoader() {
+ Column(
+ verticalArrangement = Arrangement.Center,
+ horizontalGravity = Alignment.CenterHorizontally
+ ) {
+ CircularProgressIndicator(
+ color = NewzzTheme.colors.circularLoaderColor
+ )
+ }
+}
+
+@Composable
+fun ErrorView(
+ errorMessage: String,
+ showRetry: Boolean,
+ retry: () -> Unit
+) {
+ Column(
+ verticalArrangement = Arrangement.Center,
+ horizontalGravity = Alignment.CenterHorizontally
+ ) {
+ Text(
+ text = errorMessage,
+ style = articleTitleStyle.copy(color = NewzzTheme.colors.titleColor)
+ )
+ if (showRetry) {
+ TextButton(onClick = retry) {
+ Text(
+ text = stringResource(id = R.string.retry),
+ style = TextStyle(
+ color = NewzzTheme.colors.sourceColor
+ )
+ )
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/TopAppBar.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/TopAppBar.kt
new file mode 100644
index 0000000..6f9997d
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/TopAppBar.kt
@@ -0,0 +1,62 @@
+package com.akash.newzz_compose.ui.newzzappui
+
+import androidx.annotation.StringRes
+import androidx.compose.foundation.Box
+import androidx.compose.foundation.Icon
+import androidx.compose.foundation.Text
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.material.IconButton
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.res.vectorResource
+import androidx.compose.ui.unit.dp
+import com.akash.newzz_compose.R
+import com.akash.newzz_compose.ui.style.categoryTitleStyle
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+@Composable
+fun TopAppBar(@StringRes titleResource: Int, onThemeSwitch: () -> Unit) {
+ Row(
+ modifier = Modifier.fillMaxWidth(),
+ horizontalArrangement = Arrangement.SpaceBetween,
+ verticalGravity = Alignment.CenterVertically
+ ) {
+ Text(
+ modifier = Modifier.padding(top = 40.dp, start = 16.dp, end = 16.dp, bottom = 16.dp),
+ text = stringResource(id = titleResource),
+ style = categoryTitleStyle
+ )
+ Box(modifier = Modifier.padding(top = 24.dp, end = 8.dp)) {
+ ThemeSwitcher(onThemeSwitch = {
+ onThemeSwitch()
+ })
+ }
+ }
+}
+
+@Composable
+fun ThemeSwitcher(onThemeSwitch: () -> Unit) {
+ val isDark = remember { mutableStateOf(false) }
+ val light = vectorResource(id = R.drawable.ic_light)
+ val dark = vectorResource(id = R.drawable.ic_dark)
+ IconButton(onClick = {
+ onThemeSwitch()
+ isDark.value = !isDark.value
+ }) {
+ Icon(
+ asset = if (isDark.value) light else dark,
+ tint = Color.White
+ )
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt b/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt
new file mode 100644
index 0000000..57bf83d
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt
@@ -0,0 +1,31 @@
+package com.akash.newzz_compose.ui.style
+
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.unit.sp
+
+/**
+ * Created by Akash on 28/08/20
+ */
+
+val categoryTitleStyle = TextStyle(
+ fontWeight = FontWeight.SemiBold,
+ fontSize = 20.sp,
+ letterSpacing = 1.1.sp,
+ color = Color.White
+)
+
+val articleTitleStyle = TextStyle(
+ fontWeight = FontWeight.Medium,
+ fontSize = 16.sp
+)
+
+val sourceTextStyle = TextStyle(
+ fontSize = 14.sp
+)
+
+val dateTextStyle = TextStyle(
+ fontWeight = FontWeight.ExtraLight,
+ fontSize = 12.sp
+)
diff --git a/app/src/main/java/com/akash/newzz_compose/ui/style/Theme.kt b/app/src/main/java/com/akash/newzz_compose/ui/style/Theme.kt
new file mode 100644
index 0000000..9a3a6b5
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/ui/style/Theme.kt
@@ -0,0 +1,156 @@
+package com.akash.newzz_compose.ui.style
+
+
+import androidx.compose.material.Colors
+import androidx.compose.material.MaterialTheme
+import androidx.compose.runtime.*
+import androidx.compose.ui.graphics.Color
+
+/**
+ * Created by Akash on 28/08/20
+ */
+val deepPurple = Color(0xFF4a148c)
+val darkColor = Color(0xFF121212)
+
+val sourceTextColor = Color(0xFF474646)
+val sourceTextColorDark = Color(0xFF868080)
+
+val titleColor = Color.Black
+val titleColorDark = Color(0xB3DCDCDC)
+
+val listBackgroundColor = Color.White
+val listBackgroundColorDark = Color(0xFF1E1E1E)
+
+val bottomNavBackground = Color.White
+val bottomNavBackgroundDark = Color(0xFF222222)
+
+val bottomNavIconActiveColor = Color(0xFF4a148c)
+val bottomNavIconInActiveColor = Color.Black
+
+val bottomNavIconActiveColorDark = Color(0xB3DCDCDC)
+val bottomNavIconInActiveColorDark = Color(0xFF5C5757)
+
+val circularLoaderColor = deepPurple
+val circularLoaderColorDark = Color.White
+
+val dividerColor = Color(0xFFDCDCDC)
+val dividerColorDark = Color(0xFF2B2929)
+
+private val LightColorPalette = NewzzColorPalette(
+ primaryColor = deepPurple,
+ backGroundColor = listBackgroundColor,
+ dividerColor = dividerColor,
+ titleColor = titleColor,
+ sourceColor = sourceTextColor,
+ bottomNavBackground = bottomNavBackground,
+ circularLoaderColor = circularLoaderColor,
+ bottomNavActiveIconColor = bottomNavIconActiveColor,
+ bottomNavInActiveIconColor = bottomNavIconInActiveColor,
+ isDark = false
+)
+
+private val DarkColorPalette = NewzzColorPalette(
+ primaryColor = darkColor,
+ backGroundColor = listBackgroundColorDark,
+ dividerColor = dividerColorDark,
+ titleColor = titleColorDark,
+ sourceColor = sourceTextColorDark,
+ bottomNavBackground = bottomNavBackgroundDark,
+ circularLoaderColor = circularLoaderColorDark,
+ bottomNavActiveIconColor = bottomNavIconActiveColorDark,
+ bottomNavInActiveIconColor = bottomNavIconInActiveColorDark,
+ isDark = true
+)
+
+@Composable
+fun NewzzTheme(
+ darkTheme: Boolean,
+ content: @Composable () -> Unit
+) {
+ val colors = if (darkTheme) DarkColorPalette else LightColorPalette
+ ProvideNewzzColors(colors) {
+ MaterialTheme(
+ colors = debugColors(darkTheme),
+ content = content
+ )
+ }
+}
+
+object NewzzTheme {
+ @Composable
+ val colors: NewzzColorPalette
+ get() = NewzzColorAmbient.current
+}
+
+/**
+ * Jetsnack custom Color Palette
+ */
+@Stable
+class NewzzColorPalette(
+ primaryColor: Color,
+ backGroundColor: Color,
+ dividerColor: Color,
+ titleColor: Color,
+ sourceColor: Color,
+ bottomNavBackground: Color,
+ circularLoaderColor: Color,
+ bottomNavActiveIconColor: Color,
+ bottomNavInActiveIconColor: Color,
+ isDark: Boolean
+) {
+ var primaryColor by mutableStateOf(primaryColor)
+ private set
+ var backGroundColor by mutableStateOf(backGroundColor)
+ private set
+ var dividerColor by mutableStateOf(dividerColor)
+ private set
+ var titleColor by mutableStateOf(titleColor)
+ private set
+ var sourceColor by mutableStateOf(sourceColor)
+ private set
+ var bottomNavBackground by mutableStateOf(bottomNavBackground)
+ private set
+ var circularLoaderColor by mutableStateOf(circularLoaderColor)
+ private set
+ var bottomNavActiveIconColor by mutableStateOf(bottomNavActiveIconColor)
+ private set
+ var bottomNavInActiveIconColor by mutableStateOf(bottomNavInActiveIconColor)
+ private set
+ var isDark by mutableStateOf(isDark)
+ private set
+}
+
+@Composable
+fun ProvideNewzzColors(
+ colors: NewzzColorPalette,
+ content: @Composable () -> Unit
+) {
+ Providers(NewzzColorAmbient provides colors, children = content)
+}
+
+private val NewzzColorAmbient = staticAmbientOf {
+ error("No NewzzColorPalette provided")
+}
+
+/**
+ * A Material [Colors] implementation which sets all colors to [debugColor] to discourage usage of
+ * [MaterialTheme.colors] in preference to [NewzzTheme.colors].
+ */
+fun debugColors(
+ darkTheme: Boolean,
+ debugColor: Color = Color(0x1f000000)
+) = Colors(
+ primary = debugColor,
+ primaryVariant = debugColor,
+ secondary = debugColor,
+ secondaryVariant = debugColor,
+ background = debugColor,
+ surface = debugColor,
+ error = debugColor,
+ onPrimary = debugColor,
+ onSecondary = debugColor,
+ onBackground = debugColor,
+ onSurface = debugColor,
+ onError = debugColor,
+ isLight = !darkTheme
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt b/app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt
new file mode 100644
index 0000000..c0033dc
--- /dev/null
+++ b/app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt
@@ -0,0 +1,60 @@
+package com.akash.newzz_compose.util
+
+import android.content.Context
+import android.net.Uri
+import androidx.browser.customtabs.CustomTabsIntent
+import androidx.core.content.ContextCompat
+import com.akash.newzz_compose.R
+
+/**
+ * Created by Akash on 29/08/20
+ */
+object CustomTabUtil {
+
+ private var builder: CustomTabsIntent? = null
+ private var builderDark: CustomTabsIntent? = null
+
+ fun launch(context: Context, url: String, isDark: Boolean) {
+ if (isDark) {
+ if (builderDark == null) {
+ builderDark = CustomTabsIntent.Builder()
+ .setToolbarColor(
+ ContextCompat.getColor(context, R.color.darkTheme)
+ )
+ .setShowTitle(true)
+ .setStartAnimations(
+ context,
+ R.anim.slide_in_right,
+ R.anim.slide_out_left
+ )
+ .setExitAnimations(
+ context,
+ android.R.anim.slide_in_left,
+ android.R.anim.slide_out_right
+ )
+ .build()
+ }
+ builderDark?.launchUrl(context, Uri.parse(url))
+ } else {
+ if (builder == null) {
+ builder = CustomTabsIntent.Builder()
+ .setToolbarColor(
+ ContextCompat.getColor(context, R.color.lightTheme)
+ )
+ .setShowTitle(true)
+ .setStartAnimations(
+ context,
+ R.anim.slide_in_right,
+ R.anim.slide_out_left
+ )
+ .setExitAnimations(
+ context,
+ android.R.anim.slide_in_left,
+ android.R.anim.slide_out_right
+ )
+ .build()
+ }
+ builder?.launchUrl(context, Uri.parse(url))
+ }
+ }
+}
diff --git a/app/src/main/java/com/akash/newzz_compose/utils/CustomTabUtil.kt b/app/src/main/java/com/akash/newzz_compose/utils/CustomTabUtil.kt
deleted file mode 100644
index a4a0302..0000000
--- a/app/src/main/java/com/akash/newzz_compose/utils/CustomTabUtil.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.akash.newzz_compose.utils
-
-import android.content.Context
-import android.net.Uri
-import androidx.browser.customtabs.CustomTabsIntent
-import androidx.core.content.ContextCompat
-import com.akash.newzz_compose.R
-
-/**
- * Created by Akash on 07/06/20
- */
-object CustomTabUtil {
- private var builder: CustomTabsIntent? = null
- private var builderDark: CustomTabsIntent? = null
-
- fun launch(context: Context, url: String, isDark: Boolean) {
- if (isDark) {
- if (builderDark == null) {
- builderDark = CustomTabsIntent.Builder()
- .setToolbarColor(
- ContextCompat.getColor(context, R.color.darkTheme)
- )
- .setShowTitle(true)
- .setStartAnimations(
- context,
- R.anim.slide_in_right,
- R.anim.slide_out_left
- )
- .setExitAnimations(
- context,
- android.R.anim.slide_in_left,
- android.R.anim.slide_out_right
- )
- .build()
- }
- builderDark?.launchUrl(context, Uri.parse(url))
- } else {
- if (builder == null) {
- builder = CustomTabsIntent.Builder()
- .setToolbarColor(
- ContextCompat.getColor(context, R.color.lightTheme)
- )
- .setShowTitle(true)
- .setStartAnimations(
- context,
- R.anim.slide_in_right,
- R.anim.slide_out_left
- )
- .setExitAnimations(
- context,
- android.R.anim.slide_in_left,
- android.R.anim.slide_out_right
- )
- .build()
- }
- builder?.launchUrl(context, Uri.parse(url))
- }
- }
-}
diff --git a/app/src/main/java/com/akash/newzz_compose/viewmodel/NewzzViewModel.kt b/app/src/main/java/com/akash/newzz_compose/viewmodel/NewzzViewModel.kt
index a05d49a..83f3bd8 100644
--- a/app/src/main/java/com/akash/newzz_compose/viewmodel/NewzzViewModel.kt
+++ b/app/src/main/java/com/akash/newzz_compose/viewmodel/NewzzViewModel.kt
@@ -1,210 +1,171 @@
package com.akash.newzz_compose.viewmodel
+import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
import com.akash.newzz.data.Result
import com.akash.newzz.data.repository.NewsRepository
-import com.akash.newzz.data.response.NewsArticle
-import com.akash.newzz_compose.Category
-import kotlinx.coroutines.CoroutineScope
+import com.akash.newzz.data.response.NewsResponse
+import com.akash.newzz_compose.other.Business
+import com.akash.newzz_compose.other.Category
+import com.akash.newzz_compose.other.General
+import com.akash.newzz_compose.other.Technology
+import com.akash.newzz_compose.ui.newzzappui.ArticleListUiState
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
-import kotlinx.coroutines.plus
import kotlinx.coroutines.withContext
/**
- * Created by Akash on 06/06/20
+ * Created by Akash on 28/08/20
*/
-
-class NewzzViewModel(private val repo: NewsRepository) : ViewModel() {
-
- private val job = SupervisorJob()
- private val viewModelScope = CoroutineScope(Dispatchers.Main) + job
-
- private val _pageNumber = MutableLiveData().apply {
- value = General
- }
- val pageNumber: LiveData = _pageNumber
+class NewzzViewModel @ViewModelInject constructor(private val repo: NewsRepository) : ViewModel() {
private val _isDarkTheme = MutableLiveData().apply { value = false }
val isDarkTheme: LiveData = _isDarkTheme
- private val generalArticlesListState = ArticleState()
- private val businessArticlesListState = ArticleState()
- private val techArticlesListState = ArticleState()
-
- private val _generalState = MutableLiveData().apply {
- value = generalArticlesListState
+ private val _categoryList = MutableLiveData>().apply {
+ value = listOf(General(), Business(), Technology())
}
- val generalState: LiveData = _generalState
+ val categoryList: LiveData> = _categoryList
- private val _businessState = MutableLiveData().apply {
- value = businessArticlesListState
+ private val _activeCategory = MutableLiveData().apply {
+ value = categoryList.value!![0]
}
- val businessState: LiveData = _businessState
+ val activeCategory: LiveData = _activeCategory
- private val _techState = MutableLiveData().apply {
- value = techArticlesListState
+ private val _activeCategoryUiState = MutableLiveData().apply {
+ value = ArticleListUiState()
}
- val techState: LiveData = _techState
+ val activeCategoryUiState: LiveData = _activeCategoryUiState
+
+ private var firstPageUiState = ArticleListUiState()
+ private var secondPageUiState = ArticleListUiState()
+ private var thirdPageUiState = ArticleListUiState()
init {
- performAction(Action.FetchArticles(Category.GENERAL))
+ getArticlesByCategory(categoryList.value!![0])
+ }
+
+ private fun getArticlesByCategory(
+ category: Category,
+ page: Int = 1
+ ) {
+ viewModelScope.launch {
+ setLoadingState(category)
+ when (val result = repo.getArticlesByCategoryAsync(category.category, page)) {
+ is Result.Error -> {
+ withContext(Dispatchers.Main) {
+ setErrorState(category, Result.Error(result.errorMessage, result.showRetry))
+ }
+ }
+ is Result.Success -> {
+ withContext(Dispatchers.Main) {
+ setSuccessState(category, result.data)
+ }
+ }
+ }
+ }
}
fun performAction(action: Action) {
when (action) {
is Action.ChangePageTo -> {
- _pageNumber.value = action.page
- when (action.page) {
- General -> performAction(
- Action.FetchArticles(Category.GENERAL)
- )
- Business -> performAction(
- Action.FetchArticles(Category.BUSINESS)
- )
- Technology -> performAction(
- Action.FetchArticles(Category.TECH)
- )
+ _activeCategory.value = action.category
+ when (categoryList.value!!.indexOf(action.category)) {
+ 0 -> _activeCategoryUiState.value = firstPageUiState
+ 1 -> _activeCategoryUiState.value = secondPageUiState
+ 2 -> _activeCategoryUiState.value = thirdPageUiState
}
- }
- is Action.FetchArticles -> viewModelScope.launch {
- withContext(Dispatchers.IO) {
- fetArticles(action.category)
+ if (activeCategoryUiState.value!!.list == null || activeCategoryUiState.value!!.list!!.isEmpty()) {
+ getArticlesByCategory(action.category)
}
}
- is Action.SwitchTheme -> {
+ is Action.FetchArticles -> {
+ getArticlesByCategory(action.category)
+ }
+ Action.SwitchTheme -> {
_isDarkTheme.value = !_isDarkTheme.value!!
}
}
}
- private suspend fun fetArticles(category: String) {
- when (category) {
- Category.GENERAL -> fetchGeneralArticles(category)
- Category.BUSINESS -> fetchBusinessArticles(category)
- Category.TECH -> fetchTechArticles(category)
- }
- }
-
- private suspend fun fetchGeneralArticles(category: String) {
- val state = generalState.value!!
- if (state.list == null || state.list.isEmpty()) {
- withContext(Dispatchers.Main) {
- val articleState = ArticleState()
- _generalState.value = articleState
+ private fun setErrorState(category: Category, error: Result.Error) {
+ when (categoryList.value!!.indexOf(category)) {
+ 0 -> {
+ firstPageUiState = firstPageUiState.copy(
+ isLoading = false,
+ list = null,
+ error = error
+ )
+ _activeCategoryUiState.value = firstPageUiState
}
- when (val result = repo.getArticlesByCategoryAsync(category, 1)) {
- is Result.Success -> {
- withContext(Dispatchers.Main) {
- val articleState = generalArticlesListState.copy(
- isLoading = false,
- list = result.data.articles,
- error = null
- )
- _generalState.value = articleState
- }
- }
- is Result.Error -> {
- withContext(Dispatchers.Main) {
- val articleState = generalArticlesListState.copy(
- isLoading = false,
- list = null,
- error = Error(result.errorMessage, result.showRetry)
- )
- _generalState.value = articleState
- }
- }
+ 1 -> {
+ secondPageUiState = secondPageUiState.copy(
+ isLoading = false,
+ list = null,
+ error = error
+ )
+ _activeCategoryUiState.value = secondPageUiState
+ }
+ 2 -> {
+ thirdPageUiState = thirdPageUiState.copy(
+ isLoading = false,
+ list = null,
+ error = error
+ )
+ _activeCategoryUiState.value = thirdPageUiState
}
}
}
- private suspend fun fetchBusinessArticles(category: String) {
- val state = businessState.value!!
- if (state.list == null || state.list.isEmpty()) {
- withContext(Dispatchers.Main) {
- val articleState = ArticleState()
- _businessState.value = articleState
+ private fun setSuccessState(category: Category, data: NewsResponse) {
+ when (categoryList.value!!.indexOf(category)) {
+ 0 -> {
+ firstPageUiState = firstPageUiState.copy(
+ isLoading = false,
+ list = data.articles,
+ error = null
+ )
+ _activeCategoryUiState.value = firstPageUiState
}
- when (val result = repo.getArticlesByCategoryAsync(category, 1)) {
- is Result.Success -> {
- withContext(Dispatchers.Main) {
- val articleState = businessArticlesListState.copy(
- isLoading = false,
- list = result.data.articles,
- error = null
- )
- _businessState.value = articleState
- }
- }
- is Result.Error -> {
- withContext(Dispatchers.Main) {
- val articleState = businessArticlesListState.copy(
- isLoading = false,
- list = null,
- error = Error(result.errorMessage, result.showRetry)
- )
- _businessState.value = articleState
- }
- }
+ 1 -> {
+ secondPageUiState = secondPageUiState.copy(
+ isLoading = false,
+ list = data.articles,
+ error = null
+ )
+ _activeCategoryUiState.value = secondPageUiState
+ }
+ 2 -> {
+ thirdPageUiState = thirdPageUiState.copy(
+ isLoading = false,
+ list = data.articles,
+ error = null
+ )
+ _activeCategoryUiState.value = thirdPageUiState
}
}
}
- private suspend fun fetchTechArticles(category: String) {
- val state = techState.value!!
- if (state.list == null || state.list.isEmpty()) {
- withContext(Dispatchers.Main) {
- val articleState = ArticleState()
- _techState.value = articleState
+ private fun setLoadingState(category: Category) {
+ when (categoryList.value!!.indexOf(category)) {
+ 0 -> {
+ _activeCategoryUiState.value = firstPageUiState.copy(isLoading = true)
}
- when (val result = repo.getArticlesByCategoryAsync(category, 1)) {
- is Result.Success -> {
- withContext(Dispatchers.Main) {
- val articleState = techArticlesListState.copy(
- isLoading = false,
- list = result.data.articles,
- error = null
- )
- _techState.value = articleState
- }
- }
- is Result.Error -> {
- withContext(Dispatchers.Main) {
- val articleState = techArticlesListState.copy(
- isLoading = false,
- list = null,
- error = Error(result.errorMessage, result.showRetry)
- )
- _techState.value = articleState
- }
- }
+ 1 -> {
+ _activeCategoryUiState.value = secondPageUiState.copy(isLoading = true)
+ }
+ 2 -> {
+ _activeCategoryUiState.value = thirdPageUiState.copy(isLoading = true)
}
}
}
sealed class Action {
- data class ChangePageTo(val page: Int) : Action()
- data class FetchArticles(val category: String) : Action()
+ data class ChangePageTo(val category: Category) : Action()
+ data class FetchArticles(val category: Category) : Action()
object SwitchTheme : Action()
}
-
- data class ArticleState(
- val isLoading: Boolean = true,
- val list: List? = emptyList(),
- val error: Error? = null
- )
-
- data class Error(
- val errorMessage: String,
- val showRetry: Boolean = true
- )
-
- companion object {
- const val General = 1
- const val Business = 2
- const val Technology = 3
- }
}
diff --git a/app/src/main/res/drawable/ic_light.xml b/app/src/main/res/drawable/ic_light.xml
index f674100..2815763 100644
--- a/app/src/main/res/drawable/ic_light.xml
+++ b/app/src/main/res/drawable/ic_light.xml
@@ -9,4 +9,4 @@
-
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 5577ecb..35fed59 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,3 +1,7 @@
Newzz-Compose
+ General
+ Business
+ Technology
+ Retry
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 11ed7c3..24cd47a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,16 +1,18 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
- ext.kotlin_version = "1.3.72"
- ext.compose_version = "0.1.0-dev14"
- ext.coroutines_version = "1.3.6"
- ext.koin_version = "2.1.5"
+ ext.kotlin_version = "1.4.0"
+ ext.compose_version = "1.0.0-alpha01"
+ ext.coroutines_version = "1.3.9"
+ ext.hilt_version = "2.28-alpha"
+ ext.hilt_jetpack_config_version = "1.0.0-alpha02"
repositories {
google()
jcenter()
}
dependencies {
- classpath "com.android.tools.build:gradle:4.0.0"
+ classpath "com.android.tools.build:gradle:4.0.1"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
diff --git a/data/build.gradle b/data/build.gradle
index 0275e43..b5d1ff5 100644
--- a/data/build.gradle
+++ b/data/build.gradle
@@ -2,6 +2,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
+apply plugin: 'dagger.hilt.android.plugin'
android {
compileSdkVersion 29
@@ -43,14 +44,18 @@ dependencies {
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
/*---------------------Network and Moshi----------------------------*/
- implementation 'com.squareup.retrofit2:retrofit:2.6.2'
+ implementation 'com.squareup.retrofit2:retrofit:2.7.0'
implementation 'com.squareup.okhttp3:okhttp:4.2.1'
implementation 'com.squareup.retrofit2:converter-moshi:2.6.2'
implementation 'com.squareup.moshi:moshi:1.9.1'
kapt 'com.squareup.moshi:moshi-kotlin-codegen:1.9.1'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test.ext:junit:1.1.1'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
+ /*----------------------Dagger-Hilt---------------------------------*/
+ implementation "com.google.dagger:hilt-android:$hilt_version"
+ kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
+
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test.ext:junit:1.1.2'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
\ No newline at end of file
diff --git a/data/src/main/java/com/akash/newzz/data/BaseApplication.kt b/data/src/main/java/com/akash/newzz/data/BaseApplication.kt
index f11ff0f..b270f3b 100644
--- a/data/src/main/java/com/akash/newzz/data/BaseApplication.kt
+++ b/data/src/main/java/com/akash/newzz/data/BaseApplication.kt
@@ -8,6 +8,7 @@ import android.net.ConnectivityManager
* Created by Akash on 02/07/20
*/
+@Suppress("DEPRECATION")
open class BaseApplication : Application() {
override fun onCreate() {
diff --git a/data/src/main/java/com/akash/newzz/data/repository/NewsRepositoryImpl.kt b/data/src/main/java/com/akash/newzz/data/repository/NewsRepositoryImpl.kt
index d3f4b35..3152049 100644
--- a/data/src/main/java/com/akash/newzz/data/repository/NewsRepositoryImpl.kt
+++ b/data/src/main/java/com/akash/newzz/data/repository/NewsRepositoryImpl.kt
@@ -8,15 +8,17 @@ import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
+import javax.inject.Inject
/**
* Created by Akash on 06/06/20
*/
-class NewsRepositoryImpl constructor(
+class NewsRepositoryImpl @Inject constructor(
private val newsApiService: NewzzApiService,
private val moshi: Moshi
) : NewsRepository {
+ private val defaultDispatcher = Dispatchers.Default
override suspend fun getArticlesByCategoryAsync(
category: String,
page: Int
@@ -33,7 +35,7 @@ class NewsRepositoryImpl constructor(
val jsonAdapter: JsonAdapter = moshi.adapter(
NewsError::class.java
)
- withContext(Dispatchers.IO) {
+ withContext(defaultDispatcher) {
val newsError = jsonAdapter.fromJson(response.errorBody()?.string()!!)
Result.Error(
newsError!!.message,
diff --git a/gradle.properties b/gradle.properties
index 79348a2..4145fb3 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,8 +15,8 @@ org.gradle.jvmargs=-Xmx2048M -Dkotlin.daemon.jvm.options\="-Xmx2048M"
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
-# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
+# Automatically convert third-party libraries to use AndroidX
# Kotlin code style for this project: "official" or "obsolete":
kotlin.code.style=official
org.gradle.caching=true
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 99905bf..f556fab 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip