From 018cbd9b4a25b066d72d78527513416969117a89 Mon Sep 17 00:00:00 2001 From: Akashkamble Date: Sat, 29 Aug 2020 00:26:04 +0530 Subject: [PATCH 1/4] - Migrate to Hilt. - Design container UI from scratch. - Add dynamic theming. --- .idea/compiler.xml | 6 + .idea/inspectionProfiles/Project_Default.xml | 6 + .idea/misc.xml | 2 +- .idea/vcs.xml | 6 + app/build.gradle | 49 +++-- .../java/com/akash/newzz_compose/Category.kt | 17 -- .../akash/newzz_compose/NewzzApplication.kt | 16 +- .../newzz_compose/di/NewzzActivityModule.kt | 35 ++++ .../java/com/akash/newzz_compose/di/module.kt | 20 -- .../com/akash/newzz_compose/other/Category.kt | 36 ++++ .../com/akash/newzz_compose/style/Color.kt | 34 --- .../com/akash/newzz_compose/style/Theme.kt | 24 --- .../akash/newzz_compose/ui/NewzzActivity.kt | 30 +-- .../ui/articlelist/ArticleListScreen.kt | 93 --------- .../akash/newzz_compose/ui/common/Common.kt | 73 ------- .../newzz_compose/ui/home/BodyContent.kt | 194 ----------------- .../akash/newzz_compose/ui/home/BottomBar.kt | 98 --------- .../com/akash/newzz_compose/ui/home/Home.kt | 19 -- .../newzz_compose/ui/newzzappui/BottomBar.kt | 50 +++++ .../newzz_compose/ui/newzzappui/NewzzAppUI.kt | 58 ++++++ .../newzz_compose/ui/newzzappui/TopAppBar.kt | 62 ++++++ .../newzz_compose/{ => ui}/style/TextStyle.kt | 17 +- .../com/akash/newzz_compose/ui/style/Theme.kt | 170 +++++++++++++++ .../newzz_compose/utils/CustomTabUtil.kt | 59 ------ .../newzz_compose/viewmodel/NewzzViewModel.kt | 197 +++--------------- app/src/main/res/drawable/ic_light.xml | 2 +- app/src/main/res/values/strings.xml | 3 + build.gradle | 12 +- data/build.gradle | 13 +- .../com/akash/newzz/data/BaseApplication.kt | 1 + .../data/repository/NewsRepositoryImpl.kt | 6 +- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 33 files changed, 549 insertions(+), 863 deletions(-) create mode 100644 .idea/compiler.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/vcs.xml delete mode 100644 app/src/main/java/com/akash/newzz_compose/Category.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/di/module.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/other/Category.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/style/Color.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/style/Theme.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/ui/articlelist/ArticleListScreen.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/ui/common/Common.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/ui/home/BodyContent.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/ui/home/BottomBar.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/ui/home/Home.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/TopAppBar.kt rename app/src/main/java/com/akash/newzz_compose/{ => ui}/style/TextStyle.kt (57%) create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/style/Theme.kt delete mode 100644 app/src/main/java/com/akash/newzz_compose/utils/CustomTabUtil.kt 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/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/app/build.gradle b/app/build.gradle index f339cab..11e7afb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,13 +2,14 @@ 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 @@ -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..4847151 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) - } } -} +} \ No newline at end of file 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..3b7ff40 --- /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() +} \ No newline at end of file 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..40b533a --- /dev/null +++ b/app/src/main/java/com/akash/newzz_compose/other/Category.kt @@ -0,0 +1,36 @@ +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/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..ffa5370 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,26 +1,32 @@ 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) } } } -} +} \ No newline at end of file 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/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/BottomBar.kt b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt new file mode 100644 index 0000000..2d93b57 --- /dev/null +++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/BottomBar.kt @@ -0,0 +1,50 @@ +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.BottomNavigationItem +import androidx.compose.material.Surface +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 +) { + Surface( + color = NewzzTheme.colors.bottomNavBackground, + ) { + 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..a148ca7 --- /dev/null +++ b/app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt @@ -0,0 +1,58 @@ +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!! + Scaffold( + bodyContent = { + BodyContent( + activeCategory = activeCategory, + onThemeSwitch = { + viewModel.performAction(NewzzViewModel.Action.SwitchTheme) + } + ) + }, + bottomBar = { + BottomBar( + categoryList = categoryList, + onMenuClicked = { category -> + viewModel.performAction(NewzzViewModel.Action.ChangePageTo(category)) + }, + activeCategory = activeCategory + ) + } + ) +} + +@Composable +fun BodyContent(activeCategory: Category, onThemeSwitch: () -> Unit) { + val stringRes = getTitleResource(activeCategory) + Surface( + modifier = Modifier.fillMaxSize(), + color = NewzzTheme.colors.primaryColor + ) { + Column(modifier = Modifier.fillMaxSize()) { + TopAppBar(stringRes, onThemeSwitch = { + onThemeSwitch() + }) + } + } +} + 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..aa50760 --- /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 + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt b/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt similarity index 57% rename from app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt rename to app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt index 1e1ac79..12d459f 100644 --- a/app/src/main/java/com/akash/newzz_compose/style/TextStyle.kt +++ b/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt @@ -1,17 +1,18 @@ -package com.akash.newzz_compose.style +package com.akash.newzz_compose.ui.style -import androidx.ui.graphics.Color -import androidx.ui.text.TextStyle -import androidx.ui.text.font.FontWeight -import androidx.ui.unit.sp +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 07/06/20 + * Created by Akash on 28/08/20 */ val categoryTitleStyle = TextStyle( - fontWeight = FontWeight.Bold, + fontWeight = FontWeight.SemiBold, fontSize = 20.sp, + letterSpacing = 1.1.sp, color = Color.White ) @@ -30,4 +31,4 @@ val dateTextStyle = TextStyle( fontWeight = FontWeight.ExtraLight, fontSize = 12.sp, color = sourceTextColor -) +) \ No newline at end of file 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..b3a4b1a --- /dev/null +++ b/app/src/main/java/com/akash/newzz_compose/ui/style/Theme.kt @@ -0,0 +1,170 @@ +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 = false +) + +@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 + + fun update(other: NewzzColorPalette) { + primaryColor = other.primaryColor + backGroundColor = other.backGroundColor + dividerColor = other.dividerColor + titleColor = other.titleColor + sourceColor = other.sourceColor + bottomNavBackground = other.bottomNavBackground + circularLoaderColor = other.circularLoaderColor + bottomNavActiveIconColor = other.bottomNavActiveIconColor + bottomNavInActiveIconColor = other.bottomNavInActiveIconColor + isDark = other.isDark + } +} + +@Composable +fun ProvideNewzzColors( + colors: NewzzColorPalette, + content: @Composable () -> Unit +) { +// colors.update(colors) + 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.Magenta +) = 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/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..e41dd68 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,75 @@ package com.akash.newzz_compose.viewmodel +import android.util.Log +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 kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.SupervisorJob +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 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 - } - val generalState: LiveData = _generalState - - private val _businessState = MutableLiveData().apply { - value = businessArticlesListState - } - val businessState: LiveData = _businessState - - private val _techState = MutableLiveData().apply { - value = techArticlesListState + private val _categoryList = MutableLiveData>().apply { + value = listOf(General(), Business(), Technology()) } - val techState: LiveData = _techState + val categoryList: LiveData> = _categoryList - init { - performAction(Action.FetchArticles(Category.GENERAL)) + private val _activeCategory = MutableLiveData().apply { + value = categoryList.value!![0] } + val activeCategory: LiveData = _activeCategory 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 } - is Action.FetchArticles -> viewModelScope.launch { - withContext(Dispatchers.IO) { - fetArticles(action.category) - } + is Action.FetchArticles -> { + } - is Action.SwitchTheme -> { + Action.SwitchTheme -> { _isDarkTheme.value = !_isDarkTheme.value!! + Log.d("TAG", "toggle: ${_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 - } - when (val result = repo.getArticlesByCategoryAsync(category, 1)) { + fun getArticlesByCategory( + category: String, + page: Int = 1, + ) { + viewModelScope.launch { + val result = repo.getArticlesByCategoryAsync(category, page) + when (result) { is Result.Success -> { - withContext(Dispatchers.Main) { - val articleState = generalArticlesListState.copy( - isLoading = false, - list = result.data.articles, - error = null - ) - _generalState.value = articleState - } + Log.d("TAG", "list: ${result.data.articles}") } is Result.Error -> { - withContext(Dispatchers.Main) { - val articleState = generalArticlesListState.copy( - isLoading = false, - list = null, - error = Error(result.errorMessage, result.showRetry) - ) - _generalState.value = articleState - } - } - } - } - } + Log.d("TAG", "error : ${result.errorMessage}") - 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 - } - 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 - } } } } } - 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 - } - 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 - } - } - } - } - } sealed class Action { - data class ChangePageTo(val page: Int) : Action() + data class ChangePageTo(val category: Category) : Action() data class FetchArticles(val category: String) : 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 - } -} +} \ No newline at end of file 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..b1321db 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,6 @@ Newzz-Compose + General + Business + Technology \ 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 From 12445c76fa4a3b4996018d47b2856177db199f60 Mon Sep 17 00:00:00 2001 From: Akashkamble Date: Sat, 29 Aug 2020 17:42:02 +0530 Subject: [PATCH 2/4] - Add article list with it's states. --- .idea/gradle.xml | 1 + .../ui/commoncomposable/CommonComposables.kt | 81 +++++++++++ .../ui/newzzappui/ArticleList.kt | 86 ++++++++++++ .../ui/newzzappui/ArticleListUiState.kt | 14 ++ .../newzz_compose/ui/newzzappui/BottomBar.kt | 31 +++-- .../newzz_compose/ui/newzzappui/NewzzAppUI.kt | 56 +++++--- .../ui/newzzappui/NewzzListContainer.kt | 98 +++++++++++++ .../akash/newzz_compose/ui/style/TextStyle.kt | 3 - .../com/akash/newzz_compose/ui/style/Theme.kt | 38 ++--- .../akash/newzz_compose/util/CustomTabUtil.kt | 60 ++++++++ .../newzz_compose/viewmodel/NewzzViewModel.kt | 131 +++++++++++++++--- app/src/main/res/values/strings.xml | 1 + 12 files changed, 519 insertions(+), 81 deletions(-) create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/commoncomposable/CommonComposables.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleList.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/ArticleListUiState.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/ui/newzzappui/NewzzListContainer.kt create mode 100644 app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt 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/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..046de7c --- /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) + ) + } + } + ) + } + } + } +} \ No newline at end of file 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..517fe0c --- /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) + } + ) + } + ) +} \ No newline at end of file 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..c27d044 --- /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 +) \ No newline at end of file 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 index 2d93b57..f2960a8 100644 --- 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 @@ -5,8 +5,8 @@ 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.material.Surface import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.compose.ui.res.vectorResource @@ -20,26 +20,27 @@ import com.akash.newzz_compose.ui.style.NewzzTheme @Composable fun BottomBar( - categoryList: List, - activeCategory: Category, - onMenuClicked: (Category) -> Unit + categoryList: List, + activeCategory: Category, + onMenuClicked: (Category) -> Unit ) { - Surface( - color = NewzzTheme.colors.bottomNavBackground, + BottomAppBar( + backgroundColor = NewzzTheme.colors.bottomNavBackground, + elevation = 10.dp ) { Row( - modifier = Modifier.fillMaxWidth().preferredHeight(50.dp), - horizontalArrangement = Arrangement.SpaceAround + 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 + 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 index a148ca7..42cc710 100644 --- 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 @@ -20,38 +20,54 @@ import com.akash.newzz_compose.viewmodel.NewzzViewModel 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) - } - ) - }, - bottomBar = { - BottomBar( - categoryList = categoryList, - onMenuClicked = { category -> - viewModel.performAction(NewzzViewModel.Action.ChangePageTo(category)) - }, - activeCategory = activeCategory - ) - } + 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, onThemeSwitch: () -> Unit) { +fun BodyContent( + activeCategory: Category, + activeCategoryUiState: ArticleListUiState, + onThemeSwitch: () -> Unit, + retryFetchingArticles: (Category) -> Unit +) { val stringRes = getTitleResource(activeCategory) Surface( - modifier = Modifier.fillMaxSize(), - color = NewzzTheme.colors.primaryColor + 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..3c66a32 --- /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/style/TextStyle.kt b/app/src/main/java/com/akash/newzz_compose/ui/style/TextStyle.kt index 12d459f..b548206 100644 --- 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 @@ -19,16 +19,13 @@ val categoryTitleStyle = TextStyle( 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 ) \ No newline at end of file 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 index b3a4b1a..9a3a6b5 100644 --- 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 @@ -50,16 +50,16 @@ private val LightColorPalette = NewzzColorPalette( ) private val DarkColorPalette = NewzzColorPalette( - primaryColor = darkColor, - backGroundColor = listBackgroundColorDark, - dividerColor = dividerColorDark, - titleColor = titleColorDark, - sourceColor = sourceTextColorDark, - bottomNavBackground = bottomNavBackgroundDark, - circularLoaderColor = circularLoaderColorDark, - bottomNavActiveIconColor = bottomNavIconActiveColorDark, - bottomNavInActiveIconColor = bottomNavIconInActiveColorDark, - isDark = false + primaryColor = darkColor, + backGroundColor = listBackgroundColorDark, + dividerColor = dividerColorDark, + titleColor = titleColorDark, + sourceColor = sourceTextColorDark, + bottomNavBackground = bottomNavBackgroundDark, + circularLoaderColor = circularLoaderColorDark, + bottomNavActiveIconColor = bottomNavIconActiveColorDark, + bottomNavInActiveIconColor = bottomNavIconInActiveColorDark, + isDark = true ) @Composable @@ -118,19 +118,6 @@ class NewzzColorPalette( private set var isDark by mutableStateOf(isDark) private set - - fun update(other: NewzzColorPalette) { - primaryColor = other.primaryColor - backGroundColor = other.backGroundColor - dividerColor = other.dividerColor - titleColor = other.titleColor - sourceColor = other.sourceColor - bottomNavBackground = other.bottomNavBackground - circularLoaderColor = other.circularLoaderColor - bottomNavActiveIconColor = other.bottomNavActiveIconColor - bottomNavInActiveIconColor = other.bottomNavInActiveIconColor - isDark = other.isDark - } } @Composable @@ -138,7 +125,6 @@ fun ProvideNewzzColors( colors: NewzzColorPalette, content: @Composable () -> Unit ) { -// colors.update(colors) Providers(NewzzColorAmbient provides colors, children = content) } @@ -151,8 +137,8 @@ private val NewzzColorAmbient = staticAmbientOf { * [MaterialTheme.colors] in preference to [NewzzTheme.colors]. */ fun debugColors( - darkTheme: Boolean, - debugColor: Color = Color.Magenta + darkTheme: Boolean, + debugColor: Color = Color(0x1f000000) ) = Colors( primary = debugColor, primaryVariant = debugColor, 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..713ac42 --- /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)) + } + } +} \ No newline at end of file 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 e41dd68..e082f64 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,6 +1,5 @@ package com.akash.newzz_compose.viewmodel -import android.util.Log import androidx.hilt.lifecycle.ViewModelInject import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData @@ -8,11 +7,15 @@ 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.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.launch +import kotlinx.coroutines.withContext /** * Created by Akash on 28/08/20 @@ -32,36 +35,130 @@ class NewzzViewModel @ViewModelInject constructor(private val repo: NewsReposito } val activeCategory: LiveData = _activeCategory + private val _activeCategoryUiState = MutableLiveData().apply { + value = ArticleListUiState() + } + val activeCategoryUiState: LiveData = _activeCategoryUiState + + private var firstPageUiState = ArticleListUiState() + private var secondPageUiState = ArticleListUiState() + private var thirdPageUiState = ArticleListUiState() + + init { + 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 -> { _activeCategory.value = action.category + when (categoryList.value!!.indexOf(action.category)) { + 0 -> _activeCategoryUiState.value = firstPageUiState + 1 -> _activeCategoryUiState.value = secondPageUiState + 2 -> _activeCategoryUiState.value = thirdPageUiState + } + if (activeCategoryUiState.value!!.list == null || activeCategoryUiState.value!!.list!!.isEmpty()) { + getArticlesByCategory(action.category) + } } is Action.FetchArticles -> { - + getArticlesByCategory(action.category) } Action.SwitchTheme -> { _isDarkTheme.value = !_isDarkTheme.value!! - Log.d("TAG", "toggle: ${_isDarkTheme.value}") } } } + 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 + } + 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 + } + } + } - fun getArticlesByCategory( - category: String, - page: Int = 1, - ) { - viewModelScope.launch { - val result = repo.getArticlesByCategoryAsync(category, page) - when (result) { - is Result.Success -> { - Log.d("TAG", "list: ${result.data.articles}") - } - is Result.Error -> { - Log.d("TAG", "error : ${result.errorMessage}") + 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 + } + 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 fun setLoadingState(category: Category) { + when (categoryList.value!!.indexOf(category)) { + 0 -> { + _activeCategoryUiState.value = firstPageUiState.copy(isLoading = true) + } + 1 -> { + _activeCategoryUiState.value = secondPageUiState.copy(isLoading = true) + } + 2 -> { + _activeCategoryUiState.value = thirdPageUiState.copy(isLoading = true) } } } @@ -69,7 +166,7 @@ class NewzzViewModel @ViewModelInject constructor(private val repo: NewsReposito sealed class Action { data class ChangePageTo(val category: Category) : Action() - data class FetchArticles(val category: String) : Action() + data class FetchArticles(val category: Category) : Action() object SwitchTheme : Action() } } \ 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 b1321db..35fed59 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,4 +3,5 @@ General Business Technology + Retry \ No newline at end of file From f495efd4077ff9948f74421094c28b2786a95370 Mon Sep 17 00:00:00 2001 From: Akashkamble Date: Sat, 29 Aug 2020 18:00:54 +0530 Subject: [PATCH 3/4] KtLint format. --- .../java/com/akash/newzz_compose/NewzzApplication.kt | 2 +- .../akash/newzz_compose/di/NewzzActivityModule.kt | 2 +- .../java/com/akash/newzz_compose/other/Category.kt | 2 -- .../java/com/akash/newzz_compose/ui/NewzzActivity.kt | 2 +- .../ui/commoncomposable/CommonComposables.kt | 2 +- .../akash/newzz_compose/ui/newzzappui/ArticleList.kt | 2 +- .../ui/newzzappui/ArticleListUiState.kt | 2 +- .../akash/newzz_compose/ui/newzzappui/BottomBar.kt | 3 --- .../akash/newzz_compose/ui/newzzappui/NewzzAppUI.kt | 3 +-- .../ui/newzzappui/NewzzListContainer.kt | 4 ++-- .../akash/newzz_compose/ui/newzzappui/TopAppBar.kt | 2 +- .../com/akash/newzz_compose/ui/style/TextStyle.kt | 12 ++++++------ .../com/akash/newzz_compose/util/CustomTabUtil.kt | 2 +- .../akash/newzz_compose/viewmodel/NewzzViewModel.kt | 5 ++--- 14 files changed, 19 insertions(+), 26 deletions(-) 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 4847151..d41e8de 100644 --- a/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt +++ b/app/src/main/java/com/akash/newzz_compose/NewzzApplication.kt @@ -11,4 +11,4 @@ class NewzzApplication : BaseApplication() { override fun onCreate() { super.onCreate() } -} \ No newline at end of file +} 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 index 3b7ff40..9eb4249 100644 --- a/app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt +++ b/app/src/main/java/com/akash/newzz_compose/di/NewzzActivityModule.kt @@ -32,4 +32,4 @@ object NewzzActivityModule { @Provides @ActivityScoped fun provideMoshi(): Moshi = Moshi.Builder().build() -} \ No newline at end of file +} 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 index 40b533a..1082eba 100644 --- a/app/src/main/java/com/akash/newzz_compose/other/Category.kt +++ b/app/src/main/java/com/akash/newzz_compose/other/Category.kt @@ -11,7 +11,6 @@ interface Category { val icon: Int } - data class General( override val category: String = "general", override val icon: Int = R.drawable.ic_general @@ -27,7 +26,6 @@ data class 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 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 ffa5370..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 @@ -29,4 +29,4 @@ class NewzzActivity : AppCompatActivity() { } } } -} \ No newline at end of file +} 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 index 046de7c..6c09b6a 100644 --- 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 @@ -78,4 +78,4 @@ fun RemoteImage( } } } -} \ No newline at end of file +} 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 index 517fe0c..e2af57e 100644 --- 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 @@ -83,4 +83,4 @@ fun ArticleList(articles: List) { ) } ) -} \ No newline at end of file +} 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 index c27d044..3a145ee 100644 --- 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 @@ -11,4 +11,4 @@ data class ArticleListUiState( val isLoading: Boolean = true, val list: List? = emptyList(), val error: Result.Error? = null -) \ No newline at end of file +) 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 index f2960a8..5fb41e8 100644 --- 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 @@ -46,6 +46,3 @@ fun BottomBar( } } } - - - 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 index 42cc710..9370667 100644 --- 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 @@ -66,9 +66,8 @@ fun BodyContent( 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 index 3c66a32..303451a 100644 --- 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 @@ -26,7 +26,7 @@ import com.akash.newzz_compose.ui.style.articleTitleStyle @Composable fun NewzzListContainer( uiState: ArticleListUiState, - retry: () -> Unit, + retry: () -> Unit ) { Surface( color = NewzzTheme.colors.backGroundColor, @@ -50,7 +50,7 @@ fun NewzzListContainer( } uiState.list?.isEmpty() == false -> { ArticleList( - articles = uiState.list, + articles = uiState.list ) } } 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 index aa50760..6f9997d 100644 --- 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 @@ -59,4 +59,4 @@ fun ThemeSwitcher(onThemeSwitch: () -> Unit) { tint = Color.White ) } -} \ No newline at end of file +} 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 index b548206..57bf83d 100644 --- 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 @@ -17,15 +17,15 @@ val categoryTitleStyle = TextStyle( ) val articleTitleStyle = TextStyle( - fontWeight = FontWeight.Medium, - fontSize = 16.sp, + fontWeight = FontWeight.Medium, + fontSize = 16.sp ) val sourceTextStyle = TextStyle( - fontSize = 14.sp, + fontSize = 14.sp ) val dateTextStyle = TextStyle( - fontWeight = FontWeight.ExtraLight, - fontSize = 12.sp, -) \ No newline at end of file + fontWeight = FontWeight.ExtraLight, + fontSize = 12.sp +) 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 index 713ac42..c0033dc 100644 --- a/app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt +++ b/app/src/main/java/com/akash/newzz_compose/util/CustomTabUtil.kt @@ -57,4 +57,4 @@ object CustomTabUtil { builder?.launchUrl(context, Uri.parse(url)) } } -} \ No newline at end of file +} 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 e082f64..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 @@ -50,7 +50,7 @@ class NewzzViewModel @ViewModelInject constructor(private val repo: NewsReposito private fun getArticlesByCategory( category: Category, - page: Int = 1, + page: Int = 1 ) { viewModelScope.launch { setLoadingState(category) @@ -163,10 +163,9 @@ class NewzzViewModel @ViewModelInject constructor(private val repo: NewsReposito } } - sealed class Action { data class ChangePageTo(val category: Category) : Action() data class FetchArticles(val category: Category) : Action() object SwitchTheme : Action() } -} \ No newline at end of file +} From 4bbc22081e32e866a9a273c3d458c6b703a276fb Mon Sep 17 00:00:00 2001 From: Akashkamble Date: Sat, 29 Aug 2020 18:29:27 +0530 Subject: [PATCH 4/4] - Update README. - Update versionCode and versionName. --- README.md | 6 +++--- app/build.gradle | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) 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 11e7afb..2967507 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -12,8 +12,8 @@ android { 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" }