Skip to content
Open
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
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ dependencies {
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidslidinguppanel)
implementation(libs.androidx.preference.ktx)
implementation(libs.androidx.datastore)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
Expand Down
223 changes: 145 additions & 78 deletions app/src/main/java/com/darkempire78/opencalculator/MyPreferences.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,92 +2,161 @@ package com.darkempire78.opencalculator

import android.content.Context
import androidx.appcompat.app.AppCompatDelegate.*
import androidx.preference.PreferenceManager
import androidx.datastore.migrations.SharedPreferencesMigration
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.intPreferencesKey
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import com.darkempire78.opencalculator.history.History
import com.darkempire78.opencalculator.util.ScientificModeTypes
import com.google.gson.Gson
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

class MyPreferences(context: Context) {
private object PreferenceKeys {
// https://proandroiddev.com/dark-mode-on-android-app-with-kotlin-dc759fc5f0e1
val THEME = intPreferencesKey("darkempire78.opencalculator.THEME")
val FORCE_DAY_NIGHT = intPreferencesKey("darkempire78.opencalculator.FORCE_DAY_NIGHT")

val VIBRATION_STATUS = booleanPreferencesKey("darkempire78.opencalculator.KEY_VIBRATION_STATUS")
val HISTORY = stringPreferencesKey("darkempire78.opencalculator.HISTORY_ELEMENTS")
val PREVENT_PHONE_FROM_SLEEPING = booleanPreferencesKey("darkempire78.opencalculator.PREVENT_PHONE_FROM_SLEEPING")
val HISTORY_SIZE = stringPreferencesKey("darkempire78.opencalculator.HISTORY_SIZE")
val SCIENTIFIC_MODE_ENABLED_BY_DEFAULT = intPreferencesKey("darkempire78.opencalculator.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT")
val RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT = booleanPreferencesKey("darkempire78.opencalculator.RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT")
val NUMBER_PRECISION = stringPreferencesKey("darkempire78.opencalculator.NUMBER_PRECISION")
val WRITE_NUMBER_INTO_SCIENTIFIC_NOTATION = booleanPreferencesKey("darkempire78.opencalculator.WRITE_NUMBER_INTO_SCIENTIC_NOTATION") // key typo
val LONG_CLICK_TO_COPY_VALUE = booleanPreferencesKey("darkempire78.opencalculator.LONG_CLICK_TO_COPY_VALUE")
val ADD_MODULO_BUTTON = booleanPreferencesKey("darkempire78.opencalculator.ADD_MODULO_BUTTON")
val SPLIT_PARENTHESIS_BUTTON = booleanPreferencesKey("darkempire78.opencalculator.SPLIT_PARENTHESIS_BUTTON")
val DELETE_HISTORY_ON_SWIPE = booleanPreferencesKey("darkempire78.opencalculator.DELETE_HISTORY_ELEMENT_ON_SWIPE")
val AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON = booleanPreferencesKey("darkempire78.opencalculator.AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON")
val MOVE_BACK_BUTTON_LEFT = booleanPreferencesKey("darkempire78.opencalculator.MOVE_BACK_BUTTON_LEFT")
val NUMBERING_SYSTEM = intPreferencesKey("darkempire78.opencalculator.NUMBERING_SYSTEM")
val SHOW_ON_LOCK_SCREEN = booleanPreferencesKey("darkempire78.opencalculator.KEY_SHOW_ON_LOCK_SCREEN")
}

private val Context.dataStore by preferencesDataStore(
name = "datastore",
produceMigrations = { context ->
listOf(
SharedPreferencesMigration(context, context.packageName + "_preferences") { sharedPrefs, currentData ->
val mutablePreferences = currentData.toMutablePreferences()
// Migrate the scientific mode
// The migrated ordinal value according to these rules:
// - true → ScientificModeTypes.ACTIVE.ordinal (1)
// - false → ScientificModeTypes.NOT_ACTIVE.ordinal (0)
// - Invalid/unknown types → ScientificModeTypes.OFF.ordinal (2)
val oldScientificMode = sharedPrefs.getAll()[PreferenceKeys.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT.name]
val migratedValue: Int = when (oldScientificMode) {
is Boolean -> {
if (oldScientificMode) {
ScientificModeTypes.ACTIVE.ordinal
} else {
ScientificModeTypes.NOT_ACTIVE.ordinal
}
}
is Int -> {
if (oldScientificMode in ScientificModeTypes.entries.toTypedArray().indices){
oldScientificMode
} else {
ScientificModeTypes.OFF.ordinal
}
}
else -> ScientificModeTypes.OFF.ordinal
}
// set the migrated value
mutablePreferences[PreferenceKeys.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT] = migratedValue

mutablePreferences
}
)
}
)

var ctx = context
class MyPreferences(private val context: Context) {

// https://proandroiddev.com/dark-mode-on-android-app-with-kotlin-dc759fc5f0e1
companion object {
private const val THEME = "darkempire78.opencalculator.THEME"
private const val FORCE_DAY_NIGHT = "darkempire78.opencalculator.FORCE_DAY_NIGHT"

private const val KEY_VIBRATION_STATUS = "darkempire78.opencalculator.KEY_VIBRATION_STATUS"
private const val KEY_HISTORY = "darkempire78.opencalculator.HISTORY_ELEMENTS"
private const val KEY_PREVENT_PHONE_FROM_SLEEPING = "darkempire78.opencalculator.PREVENT_PHONE_FROM_SLEEPING"
private const val KEY_HISTORY_SIZE = "darkempire78.opencalculator.HISTORY_SIZE"
private const val KEY_SCIENTIFIC_MODE_ENABLED_BY_DEFAULT = "darkempire78.opencalculator.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT"
private const val KEY_RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT = "darkempire78.opencalculator.RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT"
private const val KEY_NUMBER_PRECISION = "darkempire78.opencalculator.NUMBER_PRECISION"
private const val KEY_WRITE_NUMBER_INTO_SCIENTIC_NOTATION = "darkempire78.opencalculator.WRITE_NUMBER_INTO_SCIENTIC_NOTATION"
private const val KEY_LONG_CLICK_TO_COPY_VALUE = "darkempire78.opencalculator.LONG_CLICK_TO_COPY_VALUE"
private const val KEY_ADD_MODULO_BUTTON = "darkempire78.opencalculator.ADD_MODULO_BUTTON"
private const val KEY_SPLIT_PARENTHESIS_BUTTON = "darkempire78.opencalculator.SPLIT_PARENTHESIS_BUTTON"
private const val KEY_DELETE_HISTORY_ON_SWIPE = "darkempire78.opencalculator.DELETE_HISTORY_ELEMENT_ON_SWIPE"
private const val KEY_AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON = "darkempire78.opencalculator.AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON"
private const val KEY_MOVE_BACK_BUTTON_LEFT = "darkempire78.opencalculator.MOVE_BACK_BUTTON_LEFT"
private const val KEY_NUMBERING_SYSTEM = "darkempire78.opencalculator.NUMBERING_SYSTEM"
private const val KEY_SHOW_ON_LOCK_SCREEN = "darkempire78.opencalculator.KEY_SHOW_ON_LOCK_SCREEN"
private fun <T> readSync(key: Preferences.Key<T>, default: T): T = runBlocking {
context.dataStore.data.first()[key] ?: default
}

private val preferences = PreferenceManager.getDefaultSharedPreferences(context)

var theme = preferences.getInt(THEME, -1)
set(value) = preferences.edit().putInt(THEME, value).apply()
var forceDayNight = preferences.getInt(FORCE_DAY_NIGHT, MODE_NIGHT_UNSPECIFIED)
set(value) = preferences.edit().putInt(FORCE_DAY_NIGHT, value).apply()

var vibrationMode = preferences.getBoolean(KEY_VIBRATION_STATUS, true)
set(value) = preferences.edit().putBoolean(KEY_VIBRATION_STATUS, value).apply()
private val currentScientificModeTypes= MyPreferenceMigrator.migrateScientificMode(preferences, KEY_SCIENTIFIC_MODE_ENABLED_BY_DEFAULT)
var scientificMode = preferences.getInt(KEY_SCIENTIFIC_MODE_ENABLED_BY_DEFAULT, currentScientificModeTypes)
set(value) = preferences.edit().putInt(KEY_SCIENTIFIC_MODE_ENABLED_BY_DEFAULT, value).apply()
var useRadiansByDefault = preferences.getBoolean(KEY_RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT, false)
set(value) = preferences.edit().putBoolean(KEY_RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT, value).apply()
private var history = preferences.getString(KEY_HISTORY, null)
set(value) = preferences.edit().putString(KEY_HISTORY, value).apply()
var preventPhoneFromSleepingMode = preferences.getBoolean(KEY_PREVENT_PHONE_FROM_SLEEPING, false)
set(value) = preferences.edit().putBoolean(KEY_PREVENT_PHONE_FROM_SLEEPING, value).apply()
var historySize = preferences.getString(KEY_HISTORY_SIZE, "50")
set(value) = preferences.edit().putString(KEY_HISTORY_SIZE, value).apply()
var numberPrecision = preferences.getString(KEY_NUMBER_PRECISION, "10")
set(value) = preferences.edit().putString(KEY_NUMBER_PRECISION, value).apply()
var numberIntoScientificNotation = preferences.getBoolean(KEY_WRITE_NUMBER_INTO_SCIENTIC_NOTATION, false)
set(value) = preferences.edit().putBoolean(KEY_WRITE_NUMBER_INTO_SCIENTIC_NOTATION, value).apply()
var longClickToCopyValue = preferences.getBoolean(KEY_LONG_CLICK_TO_COPY_VALUE, true)
set(value) = preferences.edit().putBoolean(KEY_LONG_CLICK_TO_COPY_VALUE, value).apply()
var addModuloButton = preferences.getBoolean(KEY_ADD_MODULO_BUTTON, true)
set(value) = preferences.edit().putBoolean(KEY_ADD_MODULO_BUTTON, value).apply()
var splitParenthesisButton = preferences.getBoolean(KEY_SPLIT_PARENTHESIS_BUTTON, false)
set(value) = preferences.edit().putBoolean(KEY_SPLIT_PARENTHESIS_BUTTON, value).apply()
var deleteHistoryOnSwipe = preferences.getBoolean(KEY_DELETE_HISTORY_ON_SWIPE, true)
set(value) = preferences.edit().putBoolean(KEY_DELETE_HISTORY_ON_SWIPE, value).apply()

var autoSaveCalculationWithoutEqualButton = preferences.getBoolean(KEY_AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON, true)
set(value) = preferences.edit().putBoolean(KEY_AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON, value).apply()

var moveBackButtonLeft = preferences.getBoolean(KEY_MOVE_BACK_BUTTON_LEFT, false)
set(value) = preferences.edit().putBoolean(KEY_MOVE_BACK_BUTTON_LEFT, value).apply()

var numberingSystem = preferences.getInt(KEY_NUMBERING_SYSTEM, 0)
set(value) = preferences.edit().putInt(KEY_NUMBERING_SYSTEM, value).apply()

var showOnLockScreen = preferences.getBoolean(KEY_SHOW_ON_LOCK_SCREEN, true)
set(value) = preferences.edit().putBoolean(KEY_SHOW_ON_LOCK_SCREEN, value).apply()
private fun <T> writeSync(key: Preferences.Key<T>, value: T) = runBlocking {
context.dataStore.edit { prefs -> prefs[key] = value }
return@runBlocking
}

var theme: Int
get() = readSync(PreferenceKeys.THEME, -1)
set(value) = writeSync(PreferenceKeys.THEME, value)

var forceDayNight: Int
get() = readSync(PreferenceKeys.FORCE_DAY_NIGHT, MODE_NIGHT_UNSPECIFIED)
set(value) = writeSync(PreferenceKeys.FORCE_DAY_NIGHT, value)

var vibrationMode: Boolean
get() = readSync(PreferenceKeys.VIBRATION_STATUS, true)
set(value) = writeSync(PreferenceKeys.VIBRATION_STATUS, value)

var scientificMode:Int
get() = readSync(PreferenceKeys.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT, ScientificModeTypes.OFF.ordinal)
set(value) = writeSync(PreferenceKeys.SCIENTIFIC_MODE_ENABLED_BY_DEFAULT, value)

var useRadiansByDefault: Boolean
get() = readSync(PreferenceKeys.RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT, false)
set(value) = writeSync(PreferenceKeys.RADIANS_INSTEAD_OF_DEGREES_BY_DEFAULT, value)

private var historyJson: String
get() = readSync(PreferenceKeys.HISTORY, "")
set(value) = writeSync(PreferenceKeys.HISTORY, value)

var preventPhoneFromSleepingMode: Boolean
get() = readSync(PreferenceKeys.PREVENT_PHONE_FROM_SLEEPING, false)
set(value) = writeSync(PreferenceKeys.PREVENT_PHONE_FROM_SLEEPING, value)
var historySize: String
get() = readSync(PreferenceKeys.HISTORY_SIZE, "50")
set(value) = writeSync(PreferenceKeys.HISTORY_SIZE, value)
var numberPrecision: String
get() = readSync(PreferenceKeys.NUMBER_PRECISION, "10")
set(value) = writeSync(PreferenceKeys.NUMBER_PRECISION, value)
var numberIntoScientificNotation: Boolean
get() = readSync(PreferenceKeys.WRITE_NUMBER_INTO_SCIENTIFIC_NOTATION, false)
set(value) = writeSync(PreferenceKeys.WRITE_NUMBER_INTO_SCIENTIFIC_NOTATION, value)
var longClickToCopyValue: Boolean
get() = readSync(PreferenceKeys.LONG_CLICK_TO_COPY_VALUE, true)
set(value) = writeSync(PreferenceKeys.LONG_CLICK_TO_COPY_VALUE, value)
var addModuloButton: Boolean
get() = readSync(PreferenceKeys.ADD_MODULO_BUTTON, true)
set(value) = writeSync(PreferenceKeys.ADD_MODULO_BUTTON, value)
var splitParenthesisButton: Boolean
get() = readSync(PreferenceKeys.SPLIT_PARENTHESIS_BUTTON, false)
set(value) = writeSync(PreferenceKeys.SPLIT_PARENTHESIS_BUTTON, value)
var deleteHistoryOnSwipe: Boolean
get() = readSync(PreferenceKeys.DELETE_HISTORY_ON_SWIPE, false)
set(value) = writeSync(PreferenceKeys.DELETE_HISTORY_ON_SWIPE, value)

var autoSaveCalculationWithoutEqualButton: Boolean
get() = readSync(PreferenceKeys.AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON, true)
set(value) = writeSync(PreferenceKeys.AUTO_SAVE_CALCULATION_WITHOUT_EQUAL_BUTTON, value)

var moveBackButtonLeft: Boolean
get() = readSync(PreferenceKeys.MOVE_BACK_BUTTON_LEFT, false)
set(value) = writeSync(PreferenceKeys.MOVE_BACK_BUTTON_LEFT, value)

var numberingSystem: Int
get() = readSync(PreferenceKeys.NUMBERING_SYSTEM, 0)
set(value) = writeSync(PreferenceKeys.NUMBERING_SYSTEM, value)

var showOnLockScreen: Boolean
get() = readSync(PreferenceKeys.SHOW_ON_LOCK_SCREEN, true)
set(value) = writeSync(PreferenceKeys.SHOW_ON_LOCK_SCREEN, value)

fun getHistory(): MutableList<History> {
val gson = Gson()

val historyJson = preferences.getString(KEY_HISTORY, null)

return if (historyJson != null) {
return if (historyJson.isNotEmpty()) {
try {
val list = gson.fromJson(historyJson, Array<History>::class.java).asList().toMutableList()
list
gson.fromJson(historyJson, Array<History>::class.java).asList().toMutableList()
} catch (e: Exception) {
mutableListOf()
}
Expand All @@ -96,15 +165,13 @@ class MyPreferences(context: Context) {
}
}



fun saveHistory(history: List<History>){
val gson = Gson()
val history2 = history.toMutableList()
while (historySize!!.toInt() > 0 && history2.size > historySize!!.toInt()) {
while (historySize.toInt() > 0 && history2.size > historySize.toInt()) {
history2.removeAt(0)
}
MyPreferences(ctx).history = gson.toJson(history2) // Convert to json
historyJson = gson.toJson(history2) // Convert to json
}

fun getHistoryElementById(id: String): History? {
Expand Down

This file was deleted.

Loading