From 23eec4ceb1dbeb6a1f833083895f4915ed5005d5 Mon Sep 17 00:00:00 2001 From: Davide Depau Date: Sun, 30 Sep 2018 18:12:21 +0200 Subject: [PATCH] Add night mode --- app/build.gradle | 14 +- .../etchdroid/activities/ActivityBase.kt | 15 ++- .../activities/ConfirmationActivity.kt | 2 +- .../etchdroid/activities/ErrorActivity.kt | 3 +- .../etchdroid/activities/StartActivity.kt | 7 +- .../utils/DoNotShowAgainDialogFragment.kt | 17 ++- .../depau/etchdroid/utils/NightModeHelper.kt | 121 ++++++++++++++++++ app/src/main/res/drawable-night/ic_dmg.xml | 16 +++ app/src/main/res/drawable-night/ic_raw.xml | 13 ++ .../main/res/drawable-night/ic_usb_200dp.xml | 5 + ...c_usb_black_200dp.xml => ic_usb_200dp.xml} | 0 .../main/res/layout/activity_confirmation.xml | 10 +- app/src/main/res/layout/activity_error.xml | 2 +- app/src/main/res/layout/activity_licenses.xml | 2 +- app/src/main/res/layout/activity_start.xml | 10 +- .../res/layout/activity_usb_drive_picker.xml | 6 +- app/src/main/res/layout/do_not_show_again.xml | 3 +- app/src/main/res/layout/license_row.xml | 2 +- app/src/main/res/layout/partition_row.xml | 3 +- app/src/main/res/layout/usb_device_row.xml | 2 +- app/src/main/res/menu/menu_main.xml | 6 + app/src/main/res/values-it-night/strings.xml | 4 + app/src/main/res/values-it/strings.xml | 1 + app/src/main/res/values-night/colors.xml | 9 ++ app/src/main/res/values-night/strings.xml | 4 + app/src/main/res/values-night/styles.xml | 19 +++ app/src/main/res/values-notnight/styles.xml | 11 ++ app/src/main/res/values/attrs.xml | 6 + app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 1 + app/src/main/res/values/styles.xml | 20 ++- gradle/wrapper/gradle-wrapper.properties | 4 +- 32 files changed, 301 insertions(+), 38 deletions(-) create mode 100644 app/src/main/java/eu/depau/etchdroid/utils/NightModeHelper.kt create mode 100644 app/src/main/res/drawable-night/ic_dmg.xml create mode 100644 app/src/main/res/drawable-night/ic_raw.xml create mode 100644 app/src/main/res/drawable-night/ic_usb_200dp.xml rename app/src/main/res/drawable/{ic_usb_black_200dp.xml => ic_usb_200dp.xml} (100%) create mode 100644 app/src/main/res/values-it-night/strings.xml create mode 100644 app/src/main/res/values-night/colors.xml create mode 100644 app/src/main/res/values-night/strings.xml create mode 100644 app/src/main/res/values-night/styles.xml create mode 100644 app/src/main/res/values-notnight/styles.xml create mode 100644 app/src/main/res/values/attrs.xml diff --git a/app/build.gradle b/app/build.gradle index 288b935..c69d09e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -26,22 +26,22 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.0.0-rc02' + implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' - implementation 'com.google.android.material:material:1.0.0-rc02' - implementation 'androidx.recyclerview:recyclerview:1.0.0-rc02' - implementation 'androidx.gridlayout:gridlayout:1.0.0-rc02' + implementation 'com.google.android.material:material:1.0.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' + implementation 'androidx.gridlayout:gridlayout:1.0.0' api 'com.google.guava:guava:26.0-android' - implementation 'com.github.codekidX:storage-chooser:2.0.4.2' + api 'com.github.codekidX:storage-chooser:2.0.4.2' // implementation 'com.github.mjdev:libaums:0.5.5' implementation project(':libaums') implementation project(':dmg2img') implementation 'com.android.support.constraint:constraint-layout:1.1.3' - implementation 'com.android.support:design:28.0.0-rc02' - implementation 'com.android.support:appcompat-v7:28.0.0-rc02' + implementation 'com.android.support:design:28.0.0' + implementation 'com.android.support:appcompat-v7:28.0.0' testImplementation 'junit:junit:4.12' androidTestImplementation 'androidx.test:runner:1.1.0-alpha4' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-alpha4' diff --git a/app/src/main/java/eu/depau/etchdroid/activities/ActivityBase.kt b/app/src/main/java/eu/depau/etchdroid/activities/ActivityBase.kt index 899d3d6..4811550 100644 --- a/app/src/main/java/eu/depau/etchdroid/activities/ActivityBase.kt +++ b/app/src/main/java/eu/depau/etchdroid/activities/ActivityBase.kt @@ -1,12 +1,21 @@ package eu.depau.etchdroid.activities import android.content.Intent +import android.os.Bundle import android.view.Menu import android.view.MenuItem import androidx.appcompat.app.AppCompatActivity import eu.depau.etchdroid.R +import eu.depau.etchdroid.utils.NightModeHelper -abstract class ActivityBase: AppCompatActivity() { + +abstract class ActivityBase : AppCompatActivity() { + protected lateinit var nightModeHelper: NightModeHelper + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + nightModeHelper = NightModeHelper(this, R.style.AppTheme) + } override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. @@ -24,6 +33,10 @@ abstract class ActivityBase: AppCompatActivity() { startActivity(intent) return true } + R.id.action_nightmode -> { + nightModeHelper.toggle() + return true + } else -> super.onOptionsItemSelected(item) } } diff --git a/app/src/main/java/eu/depau/etchdroid/activities/ConfirmationActivity.kt b/app/src/main/java/eu/depau/etchdroid/activities/ConfirmationActivity.kt index 9c99ade..69b2c4e 100644 --- a/app/src/main/java/eu/depau/etchdroid/activities/ConfirmationActivity.kt +++ b/app/src/main/java/eu/depau/etchdroid/activities/ConfirmationActivity.kt @@ -37,7 +37,7 @@ class ConfirmationActivity : ActivityBase() { fun showDataLossAlertDialog() { - val dialogFragment = DoNotShowAgainDialogFragment() + val dialogFragment = DoNotShowAgainDialogFragment(nightModeHelper.nightMode) dialogFragment.title = getString(R.string.warning) dialogFragment.message = getString(R.string.dataloss_confirmation_dialog_message) dialogFragment.positiveButton = getString(R.string.confirm_flash_image) diff --git a/app/src/main/java/eu/depau/etchdroid/activities/ErrorActivity.kt b/app/src/main/java/eu/depau/etchdroid/activities/ErrorActivity.kt index 8462d5d..50a35ed 100644 --- a/app/src/main/java/eu/depau/etchdroid/activities/ErrorActivity.kt +++ b/app/src/main/java/eu/depau/etchdroid/activities/ErrorActivity.kt @@ -1,11 +1,10 @@ package eu.depau.etchdroid.activities import android.os.Bundle -import androidx.appcompat.app.AppCompatActivity import eu.depau.etchdroid.R import kotlinx.android.synthetic.main.activity_error.* -class ErrorActivity : AppCompatActivity() { +class ErrorActivity : ActivityBase() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/eu/depau/etchdroid/activities/StartActivity.kt b/app/src/main/java/eu/depau/etchdroid/activities/StartActivity.kt index 307dd05..a7356f5 100644 --- a/app/src/main/java/eu/depau/etchdroid/activities/StartActivity.kt +++ b/app/src/main/java/eu/depau/etchdroid/activities/StartActivity.kt @@ -1,16 +1,15 @@ package eu.depau.etchdroid.activities import android.Manifest -import android.app.Activity import android.content.Intent import android.content.pm.PackageManager import android.net.Uri import android.os.Bundle import android.os.Environment import android.view.View +import androidx.appcompat.app.AppCompatActivity import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat -import com.codekidlabs.storagechooser.StorageChooser import eu.depau.etchdroid.R import eu.depau.etchdroid.StateKeeper import eu.depau.etchdroid.enums.FlashMethod @@ -62,7 +61,7 @@ class StartActivity : ActivityBase() { } fun showDMGBetaAlertDialog() { - val dialogFragment = DoNotShowAgainDialogFragment() + val dialogFragment = DoNotShowAgainDialogFragment(nightModeHelper.nightMode) dialogFragment.title = getString(R.string.here_be_dragons) dialogFragment.message = getString(R.string.dmg_alert_dialog_text) dialogFragment.positiveButton = getString(R.string.i_understand) @@ -145,7 +144,7 @@ class StartActivity : ActivityBase() { } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) { + if (requestCode == READ_REQUEST_CODE && resultCode == AppCompatActivity.RESULT_OK) { // The document selected by the user won't be returned in the intent. // Instead, a URI to that document will be contained in the return intent // provided to this method as a parameter. diff --git a/app/src/main/java/eu/depau/etchdroid/utils/DoNotShowAgainDialogFragment.kt b/app/src/main/java/eu/depau/etchdroid/utils/DoNotShowAgainDialogFragment.kt index 75da5d7..a135117 100644 --- a/app/src/main/java/eu/depau/etchdroid/utils/DoNotShowAgainDialogFragment.kt +++ b/app/src/main/java/eu/depau/etchdroid/utils/DoNotShowAgainDialogFragment.kt @@ -1,5 +1,6 @@ package eu.depau.etchdroid.utils +import android.annotation.SuppressLint import android.app.Dialog import android.os.Bundle import android.view.LayoutInflater @@ -8,13 +9,21 @@ import androidx.fragment.app.DialogFragment import eu.depau.etchdroid.R import kotlinx.android.synthetic.main.do_not_show_again.view.* - -class DoNotShowAgainDialogFragment() : DialogFragment() { +@SuppressLint("ValidFragment") +class DoNotShowAgainDialogFragment(nightMode: Boolean) : DialogFragment() { var title: String? = null var positiveButton: String? = null var negativeButton: String? = null var message: String? = null var listener: DialogListener? = null + val dialogTheme: Int + + constructor() : this(false) + + init { + dialogTheme = if (nightMode) R.style.DialogThemeDark else R.style.DialogThemeLight + setStyle(DialogFragment.STYLE_NORMAL, dialogTheme) + } interface DialogListener { fun onDialogPositive(dialog: DoNotShowAgainDialogFragment, showAgain: Boolean) @@ -23,7 +32,7 @@ class DoNotShowAgainDialogFragment() : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { // Build the dialog and set up the button click handlers - val builder = AlertDialog.Builder(activity!!) + val builder = AlertDialog.Builder(activity!!, dialogTheme) val inflater = LayoutInflater.from(this.context) val dnsaLayout = inflater.inflate(R.layout.do_not_show_again, null) val doNotShowAgainCB = dnsaLayout.do_not_show_again @@ -37,7 +46,7 @@ class DoNotShowAgainDialogFragment() : DialogFragment() { } if (negativeButton != null) - builder.setNegativeButton(negativeButton) {_, _ -> + builder.setNegativeButton(negativeButton) { _, _ -> listener?.onDialogNegative(this@DoNotShowAgainDialogFragment, !doNotShowAgainCB.isChecked) } diff --git a/app/src/main/java/eu/depau/etchdroid/utils/NightModeHelper.kt b/app/src/main/java/eu/depau/etchdroid/utils/NightModeHelper.kt new file mode 100644 index 0000000..510313b --- /dev/null +++ b/app/src/main/java/eu/depau/etchdroid/utils/NightModeHelper.kt @@ -0,0 +1,121 @@ +package eu.depau.etchdroid.utils + +import android.content.SharedPreferences +import android.content.res.Configuration +import android.preference.PreferenceManager +import androidx.appcompat.app.AppCompatActivity +import java.lang.ref.WeakReference + + +/** + * Night Mode Helper + * + * Adapted from https://gist.github.com/slightfoot/c508cdc8828a478572e0 + * + * Helps use utilise the night and notnight resource qualifiers without + * being in car or dock mode. + * + * + * Implementation is simple. Add the follow line at the top of your + * activity's onCreate just after the super.onCreate(); The idea here + * is to do it before we create any views. So the new views will use + * the correct Configuration. + * + *
+ * mNightModeHelper = new NightModeHelper(this, R.style.AppTheme);
+
* + * + * You can now use your instance of NightModeHelper to control which mode + * you are in. You can choose to persist the current setting and hand + * it back to this class as the defaultUiMode, otherwise this is done + * for you automatically. + * + * + * I'd suggest you setup your Theme as follows: + * + * * + * **res\values\styles.xml** + *
<style name="AppTheme" parent="AppBaseTheme"></style>
+ * + * * + * **res\values-night\styles.xml** + *
<style name="AppBaseTheme" parent="@android:style/Theme.Holo"></style>
+ * + * * + * **res\values-notnight\styles.xml** + *
<style name="AppBaseTheme" parent="@android:style/Theme.Holo.Light"></style>
+ * + * @author Simon Lightfoot @demondevelopers.com> + */ +class NightModeHelper { + + private var mActivity: WeakReference? = null + lateinit var mPrefs: SharedPreferences + + val nightMode: Boolean + get() = uiNightMode == Configuration.UI_MODE_NIGHT_YES + + private val PREF_KEY = "nightModeState" + + companion object { + var uiNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED + } + + /** + * Default behaviour is to automatically save the setting and restore it. + */ + constructor(activity: AppCompatActivity, theme: Int) { + val currentMode = activity.resources.configuration + .uiMode and Configuration.UI_MODE_NIGHT_MASK + mPrefs = PreferenceManager.getDefaultSharedPreferences(activity) + init(activity, theme, mPrefs.getInt(PREF_KEY, currentMode)) + } + + /** + * If you don't want the autoSave feature and instead want to provide + * your own persisted storage for the mode, use the defaultUiMode for it. + */ + constructor(activity: AppCompatActivity, theme: Int, defaultUiMode: Int) { + init(activity, theme, defaultUiMode) + } + + private fun init(activity: AppCompatActivity, theme: Int, defaultUiMode: Int) { + mActivity = WeakReference(activity) + if (uiNightMode == Configuration.UI_MODE_NIGHT_UNDEFINED) { + uiNightMode = defaultUiMode + } + updateConfig(uiNightMode) + + // This may seem pointless but it forces the Theme to be reloaded + // with new styles that would change due to new Configuration. + activity.setTheme(theme) + } + + private fun updateConfig(uiNightMode: Int) { + val activity = mActivity!!.get() + ?: throw IllegalStateException("Activity went away while switching theme") + val newConfig = Configuration(activity.resources.configuration) + newConfig.uiMode = newConfig.uiMode and Configuration.UI_MODE_NIGHT_MASK.inv() + newConfig.uiMode = newConfig.uiMode or uiNightMode + activity.resources.updateConfiguration(newConfig, null) + Companion.uiNightMode = uiNightMode + mPrefs.edit()?.putInt(PREF_KEY, Companion.uiNightMode)?.apply() + } + + fun toggle() { + when (uiNightMode) { + Configuration.UI_MODE_NIGHT_YES -> notNight() + else -> night() + } + } + + fun notNight() { + updateConfig(Configuration.UI_MODE_NIGHT_NO) + mActivity!!.get()!!.recreate() + } + + fun night() { + updateConfig(Configuration.UI_MODE_NIGHT_YES) + mActivity!!.get()!!.recreate() + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-night/ic_dmg.xml b/app/src/main/res/drawable-night/ic_dmg.xml new file mode 100644 index 0000000..b185083 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_dmg.xml @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/app/src/main/res/drawable-night/ic_raw.xml b/app/src/main/res/drawable-night/ic_raw.xml new file mode 100644 index 0000000..1812526 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_raw.xml @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/app/src/main/res/drawable-night/ic_usb_200dp.xml b/app/src/main/res/drawable-night/ic_usb_200dp.xml new file mode 100644 index 0000000..44e2387 --- /dev/null +++ b/app/src/main/res/drawable-night/ic_usb_200dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_usb_black_200dp.xml b/app/src/main/res/drawable/ic_usb_200dp.xml similarity index 100% rename from app/src/main/res/drawable/ic_usb_black_200dp.xml rename to app/src/main/res/drawable/ic_usb_200dp.xml diff --git a/app/src/main/res/layout/activity_confirmation.xml b/app/src/main/res/layout/activity_confirmation.xml index 7124c65..f49b3cf 100644 --- a/app/src/main/res/layout/activity_confirmation.xml +++ b/app/src/main/res/layout/activity_confirmation.xml @@ -6,12 +6,14 @@ android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" + android:theme="@style/DarkThemeOverlay" tools:context=".activities.ConfirmationActivity"> @@ -17,6 +18,7 @@ android:layout_height="match_parent" android:orientation="vertical" tools:context=".fragments.FlashMethodFragment" + android:background="?android:windowBackground" tools:showIn="@layout/activity_start"> @@ -96,7 +101,8 @@ android:id="@+id/btn_image_dmg" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/selectableItemBackground" + android:theme="@style/CardContentStyle" + android:foreground="?attr/selectableItemBackground" android:onClick="onButtonClicked"> + android:layout_height="match_parent" + android:theme="@style/CardContentStyle"> + android:drawableTop="@drawable/ic_usb_200dp"/> diff --git a/app/src/main/res/layout/do_not_show_again.xml b/app/src/main/res/layout/do_not_show_again.xml index 1c594c7..60c6fba 100644 --- a/app/src/main/res/layout/do_not_show_again.xml +++ b/app/src/main/res/layout/do_not_show_again.xml @@ -4,7 +4,8 @@ android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" - android:padding="10dp" > + android:padding="10dp" + android:theme="@style/CardContentStyle"> + + diff --git a/app/src/main/res/values-it-night/strings.xml b/app/src/main/res/values-it-night/strings.xml new file mode 100644 index 0000000..75780d5 --- /dev/null +++ b/app/src/main/res/values-it-night/strings.xml @@ -0,0 +1,4 @@ + + + Disattiva modalità notturna + \ No newline at end of file diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index 7d6b26e..c635e70 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -103,4 +103,5 @@ Scrittura fallita Errore sconosciuto. Prova a ricollegare il dispositivo USB o a riavviare il dispositivo. Per favore, segnala il problema su GitHub. (decompresso) + Attiva modalità notturna \ No newline at end of file diff --git a/app/src/main/res/values-night/colors.xml b/app/src/main/res/values-night/colors.xml new file mode 100644 index 0000000..a214edf --- /dev/null +++ b/app/src/main/res/values-night/colors.xml @@ -0,0 +1,9 @@ + + + #303138 + #23242a + #a5d6a7 + #888888 + #dddddd + #23242a + \ No newline at end of file diff --git a/app/src/main/res/values-night/strings.xml b/app/src/main/res/values-night/strings.xml new file mode 100644 index 0000000..d51af1c --- /dev/null +++ b/app/src/main/res/values-night/strings.xml @@ -0,0 +1,4 @@ + + + Disable night mode + \ No newline at end of file diff --git a/app/src/main/res/values-night/styles.xml b/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..4abe5ca --- /dev/null +++ b/app/src/main/res/values-night/styles.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-notnight/styles.xml b/app/src/main/res/values-notnight/styles.xml new file mode 100644 index 0000000..b8c3c06 --- /dev/null +++ b/app/src/main/res/values-notnight/styles.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index aca2f7c..8b1ff19 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Thu Sep 13 22:30:46 CEST 2018 +#Sat Sep 29 19:40:07 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip