Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds theme selector to switch between light and dark theme variants #103

Merged
merged 2 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,21 @@ package com.github.ashutoshgngwr.noice
import android.content.Intent
import android.net.Uri
import android.view.Gravity
import androidx.appcompat.app.AppCompatDelegate
import androidx.fragment.app.FragmentManager
import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ActivityScenario.launch
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.DrawerActions
import androidx.test.espresso.contrib.DrawerMatchers.isClosed
import androidx.test.espresso.contrib.NavigationViewActions
import androidx.test.espresso.intent.Intents
import androidx.test.espresso.intent.Intents.intended
import androidx.test.espresso.intent.matcher.IntentMatchers.filterEquals
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.RootMatchers.isDialog
import androidx.test.espresso.matcher.ViewMatchers.*
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.github.ashutoshgngwr.noice.fragment.AboutFragment
Expand Down Expand Up @@ -68,6 +71,37 @@ class MainActivityTest {
}
}

@Test
fun testThemeMenuItem() {
val nightModes = arrayOf(
AppCompatDelegate.MODE_NIGHT_NO,
AppCompatDelegate.MODE_NIGHT_YES,
AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
)

val themes = InstrumentationRegistry.getInstrumentation()
.targetContext
.resources
.getStringArray(R.array.app_themes)

for (i in themes.indices) {
onView(withId(R.id.layout_main))
.check(matches(isClosed(Gravity.START)))
.perform(DrawerActions.open(Gravity.START))

onView(withId(R.id.navigation_drawer))
.perform(NavigationViewActions.navigateTo(R.id.app_theme))

onView(withText(themes[i]))
.inRoot(isDialog())
.check(matches(isDisplayed()))
.perform(click())

InstrumentationRegistry.getInstrumentation().waitForIdleSync()
assertEquals(nightModes[i], AppCompatDelegate.getDefaultNightMode())
}
}

@Test
fun testAboutMenuItem() {
onView(withId(R.id.layout_main))
Expand Down
54 changes: 52 additions & 2 deletions app/src/main/java/com/github/ashutoshgngwr/noice/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.GravityCompat
import androidx.fragment.app.Fragment
import androidx.preference.PreferenceManager
import com.github.ashutoshgngwr.noice.fragment.AboutFragment
import com.github.ashutoshgngwr.noice.fragment.PresetFragment
import com.github.ashutoshgngwr.noice.fragment.SleepTimerFragment
Expand All @@ -23,14 +25,17 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte

companion object {
private const val TAG = "MainActivity"
private const val PREF_APP_THEME = "app_theme"
private const val APP_THEME_LIGHT = 0
private const val APP_THEME_DARK = 1
private const val APP_THEME_SYSTEM_DEFAULT = 2
}

private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// force night mode and use custom theme with correct color values
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
AppCompatDelegate.setDefaultNightMode(getNightModeFromPrefs())

setContentView(R.layout.activity_main)

Expand Down Expand Up @@ -97,6 +102,15 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
R.id.sleep_timer -> {
setFragment(SleepTimerFragment::class.java)
}
R.id.app_theme -> {
AlertDialog.Builder(this)
.setSingleChoiceItems(R.array.app_themes, getAppTheme()) { dialog, which ->
dialog.dismiss()
setAppTheme(which)
}
.setTitle(R.string.app_theme)
.show()
}
R.id.about -> {
setFragment(AboutFragment::class.java)
}
Expand Down Expand Up @@ -143,6 +157,42 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
}
}

/**
* Gets user setting for app theme and converts it into its corresponding value from
* array ([AppCompatDelegate.MODE_NIGHT_NO], [AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM],
* [AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM]).
*/
private fun getNightModeFromPrefs(): Int {
return when (getAppTheme()) {
APP_THEME_LIGHT -> AppCompatDelegate.MODE_NIGHT_NO
APP_THEME_DARK -> AppCompatDelegate.MODE_NIGHT_YES
APP_THEME_SYSTEM_DEFAULT -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
else -> AppCompatDelegate.MODE_NIGHT_UNSPECIFIED
}
}

/**
* Gets user setting for current app theme.
* Returns one of [APP_THEME_LIGHT], [APP_THEME_DARK] or [APP_THEME_SYSTEM_DEFAULT]
*/
private fun getAppTheme(): Int {
return PreferenceManager.getDefaultSharedPreferences(this)
.getInt(PREF_APP_THEME, APP_THEME_SYSTEM_DEFAULT)
}

/**
* Sets user setting for current app theme.
* @param newTheme should be one of [APP_THEME_LIGHT], [APP_THEME_DARK] or [APP_THEME_SYSTEM_DEFAULT]
*/
private fun setAppTheme(newTheme: Int) {
PreferenceManager.getDefaultSharedPreferences(this)
.edit()
.putInt(PREF_APP_THEME, newTheme)
.apply()

recreate()
}

private fun <T : Fragment> setFragment(fragmentClass: Class<T>) {
val tag = fragmentClass.simpleName

Expand Down
11 changes: 11 additions & 0 deletions app/src/main/res/drawable-anydpi/ic_action_theme.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#FFFFFF"
android:alpha="0.8">
<path
android:fillColor="#FF000000"
android:pathData="M20,15.31L23.31,12 20,8.69V4h-4.69L12,0.69 8.69,4H4v4.69L0.69,12 4,15.31V20h4.69L12,23.31 15.31,20H20v-4.69zM12,18V6c3.31,0 6,2.69 6,6s-2.69,6 -6,6z"/>
</vector>
Binary file added app/src/main/res/drawable-hdpi/ic_action_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-mdpi/ic_action_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-xhdpi/ic_action_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added app/src/main/res/drawable-xxhdpi/ic_action_theme.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions app/src/main/res/drawable/app_banner.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/app_banner_base"
android:tint="@color/about_description_text_color" />
6 changes: 6 additions & 0 deletions app/src/main/res/menu/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
android:title="@string/sleep_timer"
android:checkable="true" />

<item
android:id="@+id/app_theme"
android:icon="@drawable/ic_action_theme"
android:title="@string/app_theme"
android:checkable="false" />

<item
android:id="@+id/about"
android:icon="@drawable/ic_action_info"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/values-night/colors.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorBackground">#373740</color>
<color name="colorCardBackground">#33333d</color>
<color name="about_background_color">#373740</color>
<color name="colorHint">#828297</color>
</resources>
8 changes: 4 additions & 4 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<color name="colorPrimary">#27272f</color>
<color name="colorPrimaryDark">#000000</color>
<color name="colorAccent">#1eb980</color>
<color name="colorBackground">#373740</color>
<color name="colorCardBackground">#33333d</color>
<color name="about_background_color">#373740</color>
<color name="colorHint">#828297</color>
<color name="colorBackground">#f8fAf9</color>
<color name="colorCardBackground">#f1f5f4</color>
<color name="about_background_color">#f8fAf9</color>
<color name="colorHint">#7d7d68</color>
</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,10 @@
<string name="auto_sleep_schedule_error">Auto sleep timer can not be set to 00:00!</string>
<string name="auto_sleep_schedule_success">Scheduled auto sleep timer!</string>
<string name="auto_sleep_schedule_cancelled">Auto sleep timer cancelled!</string>
<string name="app_theme">Theme</string>
<string-array name="app_themes">
<item>Light</item>
<item>Dark</item>
<item>System default</item>
</string-array>
</resources>
2 changes: 1 addition & 1 deletion app/src/main/res/values/styles.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<resources>

<style name="AppTheme" parent="Theme.AppCompat">
<style name="AppTheme" parent="Theme.AppCompat.DayNight.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
Expand Down