Skip to content

Commit

Permalink
Merge pull request #14 from TheCodeMonks/Dev
Browse files Browse the repository at this point in the history
Support Dark / Light Mode using DataStore #11
  • Loading branch information
Spikeysanju authored Oct 2, 2020
2 parents c02bc8f + d4336a5 commit 00db563
Show file tree
Hide file tree
Showing 17 changed files with 163 additions and 43 deletions.
1 change: 1 addition & 0 deletions .idea/.name

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 16 additions & 1 deletion .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ android {

dependencies {

implementation 'androidx.work:work-runtime:2.3.4'
implementation 'androidx.work:work-runtime:2.4.0'
def work_version = "2.4.0"

implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
Expand All @@ -95,9 +95,12 @@ dependencies {
// Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:2.2.5"

// LiveData
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.2.0"

// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-play-services:1.3.6'

// Navigation Components
Expand All @@ -112,11 +115,13 @@ dependencies {
implementation 'io.coil-kt:coil:0.11.0'

// JSoup for HTML parsing
implementation 'org.jsoup:jsoup:1.12.1'
implementation 'org.jsoup:jsoup:1.13.1'

// Kotlin + coroutines
implementation "androidx.work:work-runtime-ktx:$work_version"

// Preferences DataStore
implementation "androidx.datastore:datastore-preferences:1.0.0-alpha01"


}
18 changes: 1 addition & 17 deletions app/src/main/java/www/thecodemonks/techbytes/NYTimes.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,5 @@
package www.thecodemonks.techbytes

import android.app.Application
import androidx.appcompat.app.AppCompatDelegate
import www.thecodemonks.techbytes.utils.isNight

class NYTimes : Application() {

override fun onCreate() {
super.onCreate()

// check for ui mode & set accordingly
val mode = if (isNight()) {
AppCompatDelegate.MODE_NIGHT_YES
} else {
AppCompatDelegate.MODE_NIGHT_NO
}

AppCompatDelegate.setDefaultNightMode(mode)
}
}
class NYTimes : Application()
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,36 @@
*
*/

package www.thecodemonks.techbytes.utils
package www.thecodemonks.techbytes.datastore

import java.util.*
import android.content.Context
import androidx.datastore.DataStore
import androidx.datastore.preferences.Preferences
import androidx.datastore.preferences.createDataStore
import androidx.datastore.preferences.edit
import androidx.datastore.preferences.preferencesKey
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map

fun isNight(): Boolean {
val currentHour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
return (currentHour <= 7 || currentHour >= 18)
class UIModePreference(context: Context) {

companion object {
private val UI_MODE_KEY = preferencesKey<Boolean>("ui_mode")
}

private val dataStore: DataStore<Preferences> = context.createDataStore(
name = "ui_mode_preference"
)

suspend fun saveToDataStore(isNightMode: Boolean) {
dataStore.edit { preferences ->
preferences[UI_MODE_KEY] = isNightMode
}
}

val uiMode: Flow<Boolean> = dataStore.data
.map { preferences ->
val uiMode = preferences[UI_MODE_KEY] ?: false
uiMode
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,15 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import kotlinx.android.synthetic.main.fragment_articles.*
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import www.thecodemonks.techbytes.R
import www.thecodemonks.techbytes.model.Category
import www.thecodemonks.techbytes.ui.adapter.CategoryAdapter
Expand Down Expand Up @@ -132,19 +136,43 @@ class ArticlesFragment : Fragment(R.layout.fragment_articles) {
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
// Inflate the menu; this adds items to the action bar if it is present.
inflater.inflate(R.menu.menu, menu)

// Set the item state
lifecycleScope.launch {
val isChecked = viewModel.readDataStore.first()
val item = menu.findItem(R.id.action_night_mode)
item.isChecked = isChecked
setUIMode(isChecked)
}
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
// Handle action bar item clicks here.
return when (item.itemId) {
R.id.action_one -> {
R.id.action_bookmark -> {
findNavController().navigate(R.id.action_articlesFragment_to_bookmarksFragment)
true
}

R.id.action_night_mode -> {
item.isChecked = !item.isChecked
setUIMode(item.isChecked)
true
}
else -> super.onOptionsItemSelected(item)
}
}

private fun setUIMode(isChecked: Boolean) {
if (isChecked) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
viewModel.saveToDataStore(true)
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
viewModel.saveToDataStore(false)
}
}

private fun setUpArticleRV() {
newsAdapter = NewsAdapter()
article_rv.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ class BaseActivity : AppCompatActivity() {
val repo = Repo(
ArticleDatabase(this)
)
val viewModelProviderFactory =
NewsViewModelProviderFactory(
repo
)

// Passing application to ViewModel for DataStore
val viewModelProviderFactory = NewsViewModelProviderFactory(this.application, repo)

viewModel =
ViewModelProvider(this, viewModelProviderFactory).get(ArticleViewModel::class.java)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,29 @@

package www.thecodemonks.techbytes.ui.viewmodel

import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import www.thecodemonks.techbytes.datastore.UIModePreference
import www.thecodemonks.techbytes.model.Article
import www.thecodemonks.techbytes.repo.Repo
import www.thecodemonks.techbytes.utils.Constants


class ArticleViewModel(private val repo: Repo) : ViewModel() {
class ArticleViewModel(application: Application, private val repo: Repo) :
AndroidViewModel(application) {

private val _articles = MutableLiveData<List<Article>>()
val articles: LiveData<List<Article>>
get() = _articles

// DataStore
private val uiDataStore = UIModePreference(application)

val currentTopic: MutableLiveData<String> by lazy {
MutableLiveData<String>().defaultTopic(Constants.NY_TECH)
}
Expand All @@ -67,6 +73,16 @@ class ArticleViewModel(private val repo: Repo) : ViewModel() {
}
}

// Get From DataStore
val readDataStore = uiDataStore.uiMode

// Save to DataStore
fun saveToDataStore(isNightMode: Boolean) {
viewModelScope.launch(IO) {
uiDataStore.saveToDataStore(isNightMode)
}
}


private fun <T : Any?> MutableLiveData<T>.defaultTopic(initialValue: T) =
apply { setValue(initialValue) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,16 @@

package www.thecodemonks.techbytes.ui.viewmodel

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import www.thecodemonks.techbytes.repo.Repo


class NewsViewModelProviderFactory(private val repo: Repo) :
class NewsViewModelProviderFactory(private val application: Application, private val repo: Repo) :
ViewModelProvider.Factory {

override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return ArticleViewModel(repo) as T
return ArticleViewModel(application, repo) as T
}
}
36 changes: 36 additions & 0 deletions app/src/main/res/drawable/ic_outline_dark.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!--
~ /*
~ * MIT License
~ *
~ * Copyright (c) 2020 Spikey Sanju
~ *
~ * Permission is hereby granted, free of charge, to any person obtaining a copy
~ * of this software and associated documentation files (the "Software"), to deal
~ * in the Software without restriction, including without limitation the rights
~ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
~ * copies of the Software, and to permit persons to whom the Software is
~ * furnished to do so, subject to the following conditions:
~ *
~ * The above copyright notice and this permission notice shall be included in all
~ * copies or substantial portions of the Software.
~ *
~ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
~ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
~ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
~ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
~ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
~ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
~ * SOFTWARE.
~ */
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M9.27,4.49c-1.63,7.54 3.75,12.41 7.66,13.8C15.54,19.38 13.81,20 12,20c-4.41,0 -8,-3.59 -8,-8C4,8.55 6.2,5.6 9.27,4.49M11.99,2.01C6.4,2.01 2,6.54 2,12c0,5.52 4.48,10 10,10c3.71,0 6.93,-2.02 8.66,-5.02c-7.51,-0.25 -12.09,-8.43 -8.32,-14.97C12.22,2.01 12.11,2.01 11.99,2.01L11.99,2.01z"/>
</vector>
8 changes: 7 additions & 1 deletion app/src/main/res/menu/menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_one"
android:id="@+id/action_bookmark"
android:icon="@drawable/ic_baseline_bookmark"
android:title="@string/bookmark"
app:showAsAction="always" />
<item
android:id="@+id/action_night_mode"
android:checkable="true"
android:icon="@drawable/ic_outline_dark"
android:title="@string/night_mode"
app:showAsAction="ifRoom" />

</menu>
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@
<string name="title_holder">Facebook Said Not to Consider Banning Political Ads</string>
<string name="desc_holder">The social network has been under intense pressure for allowing misinformation and hate speech to spread on its site.</string>
<string name="author">By Sanju S</string>

<!-- Menu -->
<string name="bookmark">Bookmark</string>
<string name="night_mode">Night Mode Switch</string>

<string name="bookmarks_holder">Bookmarks</string>
<string name="no_bookmarks">No bookmarks yet</string>
<string name="hello_blank_fragment">Hello blank fragment</string>
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.3.72"
ext.kotlin_version = "1.4.10"
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.2.0-alpha09'
classpath 'com.android.tools.build:gradle:4.2.0-alpha12'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.3.0"

Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.6-rc-6-all.zip
distributionUrl=https://services.gradle.org/distributions/gradle-6.6.1-bin.zip

0 comments on commit 00db563

Please sign in to comment.